commit
ca098490bb
12 changed files with 130 additions and 48 deletions
|
@ -1,5 +1,6 @@
|
|||
var assert = require('assert')
|
||||
var base58check = require('bs58check')
|
||||
var enforceType = require('./types')
|
||||
var networks = require('./networks')
|
||||
var scripts = require('./scripts')
|
||||
|
||||
|
@ -13,7 +14,8 @@ function findScriptTypeByVersion(version) {
|
|||
}
|
||||
|
||||
function Address(hash, version) {
|
||||
assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)
|
||||
enforceType('Buffer', hash)
|
||||
|
||||
assert.strictEqual(hash.length, 20, 'Invalid hash length')
|
||||
assert.strictEqual(version & 0xff, version, 'Invalid version byte')
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
var assert = require('assert')
|
||||
var crypto = require('./crypto')
|
||||
var enforceType = require('./types')
|
||||
|
||||
var BigInteger = require('bigi')
|
||||
var ECSignature = require('./ecsignature')
|
||||
|
||||
// https://tools.ietf.org/html/rfc6979#section-3.2
|
||||
function deterministicGenerateK(curve, hash, d) {
|
||||
assert(Buffer.isBuffer(hash), 'Hash must be a Buffer, not ' + hash)
|
||||
enforceType('Buffer', hash)
|
||||
enforceType(BigInteger, d)
|
||||
|
||||
// sanity check
|
||||
assert.equal(hash.length, 32, 'Hash must be 256 bit')
|
||||
assert(d instanceof BigInteger, 'Private key must be a BigInteger')
|
||||
|
||||
var x = d.toBuffer(32)
|
||||
var k = new Buffer(32)
|
||||
|
|
|
@ -2,6 +2,7 @@ var assert = require('assert')
|
|||
var base58check = require('bs58check')
|
||||
var crypto = require('crypto')
|
||||
var ecdsa = require('./ecdsa')
|
||||
var enforceType = require('./types')
|
||||
var networks = require('./networks')
|
||||
|
||||
var BigInteger = require('bigi')
|
||||
|
@ -46,7 +47,8 @@ ECKey.makeRandom = function(compressed, rng) {
|
|||
rng = rng || crypto.randomBytes
|
||||
|
||||
var buffer = rng(32)
|
||||
assert(Buffer.isBuffer(buffer), 'Expected Buffer, got ' + buffer)
|
||||
enforceType('Buffer', buffer)
|
||||
assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG')
|
||||
|
||||
var d = BigInteger.fromBuffer(buffer)
|
||||
d = d.mod(curve.n)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var assert = require('assert')
|
||||
var crypto = require('./crypto')
|
||||
var ecdsa = require('./ecdsa')
|
||||
var enforceType = require('./types')
|
||||
var networks = require('./networks')
|
||||
|
||||
var Address = require('./address')
|
||||
|
@ -9,10 +9,10 @@ var ecurve = require('ecurve')
|
|||
var curve = ecurve.getCurveByName('secp256k1')
|
||||
|
||||
function ECPubKey(Q, compressed) {
|
||||
assert(Q instanceof ecurve.Point, 'Expected Point, got ' + Q)
|
||||
if (compressed === undefined) compressed = true
|
||||
|
||||
if (compressed == undefined) compressed = true
|
||||
assert.strictEqual(typeof compressed, 'boolean', 'Expected boolean, got ' + compressed)
|
||||
enforceType(ecurve.Point, Q)
|
||||
enforceType('Boolean', compressed)
|
||||
|
||||
this.compressed = compressed
|
||||
this.Q = Q
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
var assert = require('assert')
|
||||
var enforceType = require('./types')
|
||||
|
||||
var BigInteger = require('bigi')
|
||||
|
||||
function ECSignature(r, s) {
|
||||
assert(r instanceof BigInteger, 'Expected BigInteger, got ' + r)
|
||||
assert(s instanceof BigInteger, 'Expected BigInteger, got ' + s)
|
||||
enforceType(BigInteger, r)
|
||||
enforceType(BigInteger, s)
|
||||
|
||||
this.r = r
|
||||
this.s = s
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var assert = require('assert')
|
||||
var base58check = require('bs58check')
|
||||
var crypto = require('./crypto')
|
||||
var enforceType = require('./types')
|
||||
var networks = require('./networks')
|
||||
|
||||
var BigInteger = require('bigi')
|
||||
|
@ -30,7 +31,8 @@ function findBIP32ParamsByVersion(version) {
|
|||
function HDNode(K, chainCode, network) {
|
||||
network = network || networks.bitcoin
|
||||
|
||||
assert(Buffer.isBuffer(chainCode), 'Expected Buffer, got ' + chainCode)
|
||||
enforceType('Buffer', chainCode)
|
||||
|
||||
assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length)
|
||||
assert(network.bip32, 'Unknown BIP32 constants for network')
|
||||
|
||||
|
@ -52,7 +54,8 @@ HDNode.HIGHEST_BIT = 0x80000000
|
|||
HDNode.LENGTH = 78
|
||||
|
||||
HDNode.fromSeedBuffer = function(seed, network) {
|
||||
assert(Buffer.isBuffer(seed), 'Expected Buffer, got ' + seed)
|
||||
enforceType('Buffer', seed)
|
||||
|
||||
assert(seed.length >= 16, 'Seed should be at least 128 bits')
|
||||
assert(seed.length <= 64, 'Seed should be at most 512 bits')
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
var assert = require('assert')
|
||||
var bufferutils = require('./bufferutils')
|
||||
var crypto = require('./crypto')
|
||||
var enforceType = require('./types')
|
||||
var opcodes = require('./opcodes')
|
||||
|
||||
function Script(buffer, chunks) {
|
||||
assert(Buffer.isBuffer(buffer), 'Expected Buffer, got ' + buffer)
|
||||
assert(Array.isArray(chunks), 'Expected Array, got ' + chunks)
|
||||
enforceType('Buffer', buffer)
|
||||
enforceType('Array', chunks)
|
||||
|
||||
this.buffer = buffer
|
||||
this.chunks = chunks
|
||||
|
@ -55,7 +56,7 @@ Script.fromBuffer = function(buffer) {
|
|||
}
|
||||
|
||||
Script.fromChunks = function(chunks) {
|
||||
assert(Array.isArray(chunks), 'Expected Array, got ' + chunks)
|
||||
enforceType('Array', chunks)
|
||||
|
||||
var bufferSize = chunks.reduce(function(accum, chunk) {
|
||||
if (Buffer.isBuffer(chunk)) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var assert = require('assert')
|
||||
var enforceType = require('./types')
|
||||
var opcodes = require('./opcodes')
|
||||
|
||||
// FIXME: use ECPubKey, currently the circular dependency breaks everything.
|
||||
|
@ -18,7 +19,7 @@ var ECSignature = require('./ecsignature')
|
|||
var Script = require('./script')
|
||||
|
||||
function classifyOutput(script) {
|
||||
assert(script instanceof Script, 'Expected Script, got ', script)
|
||||
enforceType(Script, script)
|
||||
|
||||
if (isPubKeyHashOutput.call(script)) {
|
||||
return 'pubkeyhash'
|
||||
|
@ -36,7 +37,7 @@ function classifyOutput(script) {
|
|||
}
|
||||
|
||||
function classifyInput(script) {
|
||||
assert(script instanceof Script, 'Expected Script, got ', script)
|
||||
enforceType(Script, script)
|
||||
|
||||
if (isPubKeyHashInput.call(script)) {
|
||||
return 'pubkeyhash'
|
||||
|
@ -171,7 +172,7 @@ function pubKeyOutput(pubKey) {
|
|||
|
||||
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
|
||||
function pubKeyHashOutput(hash) {
|
||||
assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)
|
||||
enforceType('Buffer', hash)
|
||||
|
||||
return Script.fromChunks([
|
||||
opcodes.OP_DUP,
|
||||
|
@ -184,7 +185,7 @@ function pubKeyHashOutput(hash) {
|
|||
|
||||
// OP_HASH160 {scriptHash} OP_EQUAL
|
||||
function scriptHashOutput(hash) {
|
||||
assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)
|
||||
enforceType('Buffer', hash)
|
||||
|
||||
return Script.fromChunks([
|
||||
opcodes.OP_HASH160,
|
||||
|
@ -195,7 +196,8 @@ function scriptHashOutput(hash) {
|
|||
|
||||
// m [pubKeys ...] n OP_CHECKMULTISIG
|
||||
function multisigOutput(m, pubKeys) {
|
||||
assert(Array.isArray(pubKeys), 'Expected Array, got ' + pubKeys)
|
||||
enforceType('Array', pubKeys)
|
||||
|
||||
assert(pubKeys.length >= m, 'Not enough pubKeys provided')
|
||||
|
||||
var pubKeyBuffers = pubKeys.map(function(pubKey) {
|
||||
|
@ -213,14 +215,14 @@ function multisigOutput(m, pubKeys) {
|
|||
|
||||
// {signature}
|
||||
function pubKeyInput(signature) {
|
||||
assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)
|
||||
enforceType('Buffer', signature)
|
||||
|
||||
return Script.fromChunks([signature])
|
||||
}
|
||||
|
||||
// {signature} {pubKey}
|
||||
function pubKeyHashInput(signature, pubKey) {
|
||||
assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)
|
||||
enforceType('Buffer', signature)
|
||||
|
||||
return Script.fromChunks([signature, pubKey.toBuffer()])
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var assert = require('assert')
|
||||
var bufferutils = require('./bufferutils')
|
||||
var crypto = require('./crypto')
|
||||
var enforceType = require('./types')
|
||||
var opcodes = require('./opcodes')
|
||||
var scripts = require('./scripts')
|
||||
|
||||
|
@ -8,12 +9,6 @@ var Address = require('./address')
|
|||
var ECSignature = require('./ecsignature')
|
||||
var Script = require('./script')
|
||||
|
||||
Transaction.DEFAULT_SEQUENCE = 0xffffffff
|
||||
Transaction.SIGHASH_ALL = 0x01
|
||||
Transaction.SIGHASH_NONE = 0x02
|
||||
Transaction.SIGHASH_SINGLE = 0x03
|
||||
Transaction.SIGHASH_ANYONECANPAY = 0x80
|
||||
|
||||
function Transaction() {
|
||||
this.version = 1
|
||||
this.locktime = 0
|
||||
|
@ -21,6 +16,12 @@ function Transaction() {
|
|||
this.outs = []
|
||||
}
|
||||
|
||||
Transaction.DEFAULT_SEQUENCE = 0xffffffff
|
||||
Transaction.SIGHASH_ALL = 0x01
|
||||
Transaction.SIGHASH_NONE = 0x02
|
||||
Transaction.SIGHASH_SINGLE = 0x03
|
||||
Transaction.SIGHASH_ANYONECANPAY = 0x80
|
||||
|
||||
/**
|
||||
* Create a new txin.
|
||||
*
|
||||
|
@ -31,26 +32,23 @@ function Transaction() {
|
|||
*
|
||||
* Note that this method does not sign the created input.
|
||||
*/
|
||||
Transaction.prototype.addInput = function(tx, index, sequence) {
|
||||
if (sequence == undefined) sequence = Transaction.DEFAULT_SEQUENCE
|
||||
Transaction.prototype.addInput = function(hash, index, sequence) {
|
||||
if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
|
||||
|
||||
var hash
|
||||
|
||||
if (typeof tx === 'string') {
|
||||
if (typeof hash === 'string') {
|
||||
// TxId hex is big-endian, we need little-endian
|
||||
hash = bufferutils.reverse(new Buffer(tx, 'hex'))
|
||||
hash = bufferutils.reverse(new Buffer(hash, 'hex'))
|
||||
|
||||
} else if (tx instanceof Transaction) {
|
||||
hash = tx.getHash()
|
||||
} else if (hash instanceof Transaction) {
|
||||
hash = hash.getHash()
|
||||
|
||||
} else {
|
||||
hash = tx
|
||||
}
|
||||
|
||||
assert(Buffer.isBuffer(hash), 'Expected Transaction, txId or txHash, got ' + tx)
|
||||
enforceType('Buffer', hash)
|
||||
enforceType('Number', index)
|
||||
enforceType('Number', sequence)
|
||||
|
||||
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
|
||||
assert(isFinite(index), 'Expected number index, got ' + index)
|
||||
assert(isFinite(sequence), 'Expected number sequence, got ' + sequence)
|
||||
|
||||
// Add the input and return the input's index
|
||||
return (this.ins.push({
|
||||
|
@ -81,8 +79,8 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
|
|||
scriptPubKey = scriptPubKey.toOutputScript()
|
||||
}
|
||||
|
||||
assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
|
||||
assert(isFinite(value), 'Expected number value, got ' + value)
|
||||
enforceType(Script, scriptPubKey)
|
||||
enforceType('Number', value)
|
||||
|
||||
// Add the output and return the output's index
|
||||
return (this.outs.push({
|
||||
|
@ -172,9 +170,12 @@ Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashTy
|
|||
prevOutScript = tmp
|
||||
}
|
||||
|
||||
enforceType('Number', inIndex)
|
||||
enforceType(Script, prevOutScript)
|
||||
enforceType('Number', hashType)
|
||||
|
||||
assert(inIndex >= 0, 'Invalid vin index')
|
||||
assert(inIndex < this.ins.length, 'Invalid vin index')
|
||||
assert(prevOutScript instanceof Script, 'Invalid Script object')
|
||||
|
||||
var txTmp = this.clone()
|
||||
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR)
|
||||
|
|
34
src/types.js
Normal file
34
src/types.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
module.exports = function enforce(type, value) {
|
||||
switch (type) {
|
||||
case 'Array': {
|
||||
if (Array.isArray(value)) return
|
||||
break
|
||||
}
|
||||
|
||||
case 'Boolean': {
|
||||
if (typeof value === 'boolean') return
|
||||
break
|
||||
}
|
||||
|
||||
case 'Buffer': {
|
||||
if (Buffer.isBuffer(value)) return
|
||||
break
|
||||
}
|
||||
|
||||
case 'Number': {
|
||||
if (typeof value === 'number') return
|
||||
break
|
||||
}
|
||||
|
||||
case 'String': {
|
||||
if (typeof value === 'string') return
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
if (value instanceof type) return
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError('Expected ' + (type.name || type) + ', got ' + value)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
var assert = require('assert')
|
||||
var bufferutils = require('./bufferutils')
|
||||
var crypto = require('crypto')
|
||||
var enforceType = require('./types')
|
||||
var networks = require('./networks')
|
||||
|
||||
var Address = require('./address')
|
||||
|
@ -300,15 +301,17 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
|
|||
index = unspent.outputIndex
|
||||
}
|
||||
|
||||
assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
|
||||
enforceType('String', txId)
|
||||
enforceType('Number', index)
|
||||
enforceType('Number', unspent.value)
|
||||
|
||||
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
|
||||
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
|
||||
assert(isFinite(index), 'Expected number index, got ' + index)
|
||||
assert.equal(typeof unspent.value, 'number', 'Expected number value, got ' + unspent.value)
|
||||
assert(isFinite(index), 'Expected finite index, got ' + index)
|
||||
|
||||
// FIXME: remove branch in 2.0.0
|
||||
if (unspent.confirmations !== undefined) {
|
||||
assert.equal(typeof unspent.confirmations, 'number', 'Expected number confirmations, got ' + unspent.confirmations)
|
||||
enforceType('Number', unspent.confirmations)
|
||||
}
|
||||
|
||||
var txHash = bufferutils.reverse(new Buffer(txId, 'hex'))
|
||||
|
|
28
test/types.js
Normal file
28
test/types.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
var assert = require('assert')
|
||||
var enforceType = require('../src/types')
|
||||
|
||||
function CustomType() {}
|
||||
|
||||
var types = ['Array', 'Boolean', 'Buffer', 'Number', 'String', CustomType]
|
||||
var values = [[], true, new Buffer(1), 1234, 'foobar', new CustomType()]
|
||||
|
||||
describe('enforceType', function() {
|
||||
types.forEach(function(type, i) {
|
||||
describe(type, function() {
|
||||
values.forEach(function(value, j) {
|
||||
if (j === i) {
|
||||
it('passes for ' + types[j], function() {
|
||||
enforceType(type, value)
|
||||
})
|
||||
|
||||
} else {
|
||||
it('fails for ' + types[j], function() {
|
||||
assert.throws(function() {
|
||||
enforceType(type, value)
|
||||
}, new RegExp('Expected ' + (type.name || type) + ', got '))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue