2015-02-23 00:36:57 +01:00
|
|
|
/* global describe, it */
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
var assert = require('assert')
|
2014-10-15 13:36:10 +02:00
|
|
|
var base58 = require('bs58')
|
|
|
|
|
|
|
|
var Bitcoin = require('../')
|
|
|
|
var Address = Bitcoin.Address
|
2015-03-04 15:14:48 +01:00
|
|
|
var Block = Bitcoin.Block
|
2015-03-02 06:48:36 +01:00
|
|
|
var ECPair = Bitcoin.ECPair
|
2014-10-15 13:36:10 +02:00
|
|
|
var ECSignature = Bitcoin.ECSignature
|
|
|
|
var Transaction = Bitcoin.Transaction
|
|
|
|
var Script = Bitcoin.Script
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-03-04 15:14:48 +01:00
|
|
|
var networks = Bitcoin.networks
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
var base58_encode_decode = require('./fixtures/core/base58_encode_decode.json')
|
|
|
|
var base58_keys_invalid = require('./fixtures/core/base58_keys_invalid.json')
|
|
|
|
var base58_keys_valid = require('./fixtures/core/base58_keys_valid.json')
|
2015-03-04 15:14:48 +01:00
|
|
|
var blocks_valid = require('./fixtures/core/blocks.json')
|
2015-02-23 00:36:57 +01:00
|
|
|
var sig_canonical = require('./fixtures/core/sig_canonical.json')
|
|
|
|
var sig_noncanonical = require('./fixtures/core/sig_noncanonical.json')
|
|
|
|
var sighash = require('./fixtures/core/sighash.json')
|
|
|
|
var tx_valid = require('./fixtures/core/tx_valid.json')
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('Bitcoin-core', function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
// base58_encode_decode
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('base58', function () {
|
|
|
|
base58_encode_decode.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
var fhex = f[0]
|
|
|
|
var fb58 = f[1]
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('can decode ' + fb58, function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var buffer = base58.decode(fb58)
|
2014-10-03 11:11:38 +02:00
|
|
|
var actual = new Buffer(buffer).toString('hex')
|
2014-05-28 17:21:56 +02:00
|
|
|
|
|
|
|
assert.equal(actual, fhex)
|
|
|
|
})
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('can encode ' + fhex, function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var buffer = new Buffer(fhex, 'hex')
|
|
|
|
var actual = base58.encode(buffer)
|
|
|
|
|
|
|
|
assert.equal(actual, fb58)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// base58_keys_valid
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('Address', function () {
|
|
|
|
var typeMap = {
|
|
|
|
'pubkey': 'pubKeyHash',
|
|
|
|
'script': 'scriptHash'
|
|
|
|
}
|
|
|
|
|
|
|
|
base58_keys_valid.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
var string = f[0]
|
|
|
|
var hex = f[1]
|
|
|
|
var params = f[2]
|
|
|
|
var network = networks.bitcoin
|
|
|
|
|
|
|
|
if (params.isPrivkey) return
|
2015-02-23 00:36:57 +01:00
|
|
|
if (params.isTestnet)
|
|
|
|
network = networks.testnet
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('can import ' + string, function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var address = Address.fromBase58Check(string)
|
|
|
|
|
|
|
|
assert.equal(address.hash.toString('hex'), hex)
|
2015-02-23 00:36:57 +01:00
|
|
|
assert.equal(address.version, network[typeMap[params.addrType]])
|
2014-05-28 17:21:56 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// base58_keys_invalid
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('Address', function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var allowedNetworks = [
|
2014-06-13 16:30:13 +02:00
|
|
|
networks.bitcoin.pubkeyhash,
|
|
|
|
networks.bitcoin.scripthash,
|
|
|
|
networks.testnet.pubkeyhash,
|
|
|
|
networks.testnet.scripthash
|
2014-05-28 17:21:56 +02:00
|
|
|
]
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
base58_keys_invalid.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
var string = f[0]
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('throws on ' + string, function () {
|
|
|
|
assert.throws(function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var address = Address.fromBase58Check(string)
|
|
|
|
|
|
|
|
assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network')
|
|
|
|
}, /Invalid (checksum|hash length|network)/)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// base58_keys_valid
|
2015-03-02 06:48:36 +01:00
|
|
|
describe('ECPair', function () {
|
2015-02-23 00:36:57 +01:00
|
|
|
base58_keys_valid.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
var string = f[0]
|
|
|
|
var hex = f[1]
|
|
|
|
var params = f[2]
|
|
|
|
|
|
|
|
if (!params.isPrivkey) return
|
2015-03-02 06:48:36 +01:00
|
|
|
var keyPair = ECPair.fromWIF(string)
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('imports ' + string + ' correctly', function () {
|
2015-03-02 06:48:36 +01:00
|
|
|
assert.equal(keyPair.d.toHex(), hex)
|
|
|
|
assert.equal(keyPair.compressed, params.isCompressed)
|
2014-05-28 17:21:56 +02:00
|
|
|
})
|
2015-02-23 00:26:01 +01:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('exports ' + hex + ' to ' + string, function () {
|
2015-03-02 06:48:36 +01:00
|
|
|
assert.equal(keyPair.toWIF(), string)
|
2015-02-23 00:26:01 +01:00
|
|
|
})
|
2014-05-28 17:21:56 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// base58_keys_invalid
|
2015-03-02 06:48:36 +01:00
|
|
|
describe('ECPair', function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var allowedNetworks = [
|
2015-03-02 06:48:36 +01:00
|
|
|
networks.bitcoin,
|
|
|
|
networks.testnet
|
2014-05-28 17:21:56 +02:00
|
|
|
]
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
base58_keys_invalid.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
var string = f[0]
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('throws on ' + string, function () {
|
|
|
|
assert.throws(function () {
|
2015-03-02 06:48:36 +01:00
|
|
|
var keyPair = ECPair.fromWIF(string)
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-03-02 06:48:36 +01:00
|
|
|
assert(allowedNetworks.indexOf(keyPair.network) > -1, 'Invalid network')
|
|
|
|
}, /(Invalid|Unknown) (checksum|compression flag|network|WIF payload)/)
|
2014-05-28 17:21:56 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2015-03-04 15:14:48 +01:00
|
|
|
describe('Block', function () {
|
|
|
|
blocks_valid.forEach(function (f) {
|
|
|
|
it('fromHex can parse ' + f.id, function () {
|
|
|
|
var block = Block.fromHex(f.hex)
|
|
|
|
|
|
|
|
assert.equal(block.getId(), f.id)
|
|
|
|
assert.equal(block.transactions.length, f.transactions)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2014-05-28 17:21:56 +02:00
|
|
|
// tx_valid
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('Transaction', function () {
|
|
|
|
tx_valid.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
// Objects that are only a single string are ignored
|
|
|
|
if (f.length === 1) return
|
|
|
|
|
|
|
|
var inputs = f[0]
|
|
|
|
var fhex = f[1]
|
2015-02-23 00:36:57 +01:00
|
|
|
// var verifyFlags = f[2] // TODO: do we need to test this?
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('can decode ' + fhex, function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var transaction = Transaction.fromHex(fhex)
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
transaction.ins.forEach(function (txin, i) {
|
2014-05-28 17:21:56 +02:00
|
|
|
var input = inputs[i]
|
|
|
|
var prevOutHash = input[0]
|
|
|
|
var prevOutIndex = input[1]
|
2015-02-23 00:36:57 +01:00
|
|
|
// var prevOutScriptPubKey = input[2] // TODO: we don't have a ASM parser
|
2014-05-28 17:21:56 +02:00
|
|
|
|
2014-06-16 06:08:43 +02:00
|
|
|
var actualHash = txin.hash
|
2014-06-14 16:03:17 +02:00
|
|
|
|
|
|
|
// Test data is big-endian
|
|
|
|
Array.prototype.reverse.call(actualHash)
|
|
|
|
|
|
|
|
assert.equal(actualHash.toString('hex'), prevOutHash)
|
2014-05-28 17:21:56 +02:00
|
|
|
|
|
|
|
// we read UInt32, not Int32
|
2014-06-16 06:08:43 +02:00
|
|
|
assert.equal(txin.index & 0xffffffff, prevOutIndex)
|
2014-05-28 17:21:56 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// sighash
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('Transaction', function () {
|
|
|
|
sighash.forEach(function (f) {
|
2014-05-28 17:21:56 +02:00
|
|
|
// Objects that are only a single string are ignored
|
|
|
|
if (f.length === 1) return
|
|
|
|
|
|
|
|
var txHex = f[0]
|
|
|
|
var scriptHex = f[1]
|
|
|
|
var inIndex = f[2]
|
|
|
|
var hashType = f[3]
|
|
|
|
var expectedHash = f[4]
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('should hash ' + txHex + ' correctly', function () {
|
2014-05-28 17:21:56 +02:00
|
|
|
var transaction = Transaction.fromHex(txHex)
|
|
|
|
assert.equal(transaction.toHex(), txHex)
|
|
|
|
|
|
|
|
var script = Script.fromHex(scriptHex)
|
|
|
|
assert.equal(script.toHex(), scriptHex)
|
|
|
|
|
|
|
|
var actualHash
|
|
|
|
try {
|
2014-07-25 08:11:45 +02:00
|
|
|
actualHash = transaction.hashForSignature(inIndex, script, hashType)
|
2014-05-28 17:21:56 +02:00
|
|
|
} catch (e) {
|
|
|
|
// don't fail if we don't support it yet, TODO
|
2015-02-23 00:36:57 +01:00
|
|
|
if (!e.message.match(/not yet supported/))
|
|
|
|
throw e
|
2014-05-28 17:21:56 +02:00
|
|
|
}
|
|
|
|
|
2014-10-15 14:06:04 +02:00
|
|
|
if (actualHash !== undefined) {
|
2014-06-14 16:03:17 +02:00
|
|
|
// Test data is big-endian
|
2014-05-28 17:21:56 +02:00
|
|
|
Array.prototype.reverse.call(actualHash)
|
|
|
|
|
|
|
|
assert.equal(actualHash.toString('hex'), expectedHash)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2014-06-20 07:25:23 +02:00
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
describe('ECSignature', function () {
|
|
|
|
sig_canonical.forEach(function (hex) {
|
2014-06-20 07:25:23 +02:00
|
|
|
var buffer = new Buffer(hex, 'hex')
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('can parse ' + hex, function () {
|
2014-06-20 07:25:23 +02:00
|
|
|
var parsed = ECSignature.parseScriptSignature(buffer)
|
|
|
|
var actual = parsed.signature.toScriptSignature(parsed.hashType)
|
|
|
|
assert.equal(actual.toString('hex'), hex)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
sig_noncanonical.forEach(function (hex, i) {
|
2014-06-20 07:25:23 +02:00
|
|
|
if (i === 0) return
|
|
|
|
if (i % 2 !== 0) return
|
|
|
|
|
|
|
|
var description = sig_noncanonical[i - 1].slice(0, -1)
|
|
|
|
if (description === 'too long') return // we support non secp256k1 signatures
|
|
|
|
|
|
|
|
var buffer = new Buffer(hex, 'hex')
|
|
|
|
|
2015-02-23 00:36:57 +01:00
|
|
|
it('throws on ' + description, function () {
|
|
|
|
assert.throws(function () {
|
2014-06-20 07:25:23 +02:00
|
|
|
ECSignature.parseScriptSignature(buffer)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2014-05-28 17:21:56 +02:00
|
|
|
})
|