Skip to content
Merged

Types #288

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/address.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var assert = require('assert')
var base58check = require('bs58check')
var enforceType = require('./types')
var networks = require('./networks')
var scripts = require('./scripts')

Expand All @@ -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')

Expand Down
7 changes: 5 additions & 2 deletions src/ecdsa.js
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
4 changes: 3 additions & 1 deletion src/eckey.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions src/ecpubkey.js
Original file line number Diff line number Diff line change
@@ -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')
Expand All @@ -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
Expand Down
7 changes: 5 additions & 2 deletions src/ecsignature.js
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
7 changes: 5 additions & 2 deletions src/hdnode.js
Original file line number Diff line number Diff line change
@@ -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')
Expand Down Expand Up @@ -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')

Expand All @@ -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')

Expand Down
7 changes: 4 additions & 3 deletions src/script.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)) {
Expand Down
16 changes: 9 additions & 7 deletions src/scripts.js
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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'
Expand All @@ -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'
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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) {
Expand All @@ -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()])
}
Expand Down
45 changes: 23 additions & 22 deletions src/transaction.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
var enforceType = require('./types')
var opcodes = require('./opcodes')
var scripts = require('./scripts')

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
this.ins = []
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.
*
Expand All @@ -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({
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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)
Expand Down
34 changes: 34 additions & 0 deletions src/types.js
Original file line number Diff line number Diff line change
@@ -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)
}
11 changes: 7 additions & 4 deletions src/wallet.js
Original file line number Diff line number Diff line change
@@ -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')
Expand Down Expand Up @@ -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'))
Expand Down
Loading