commit
848c8190c3
24 changed files with 911 additions and 944 deletions
10
.travis.yml
10
.travis.yml
|
@ -1,5 +1,13 @@
|
|||
sudo: false
|
||||
language: node_js
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- if [ $TEST_SUITE = "integration" ]; then
|
||||
docker pull junderw/bitcoinjs-regtest-server &&
|
||||
docker run -d -p 127.0.0.1:8080:8080 junderw/bitcoinjs-regtest-server &&
|
||||
docker ps -a;
|
||||
fi
|
||||
node_js:
|
||||
- "8"
|
||||
- "lts/*"
|
||||
|
@ -15,5 +23,5 @@ matrix:
|
|||
env: TEST_SUITE=coverage
|
||||
env:
|
||||
- TEST_SUITE=unit
|
||||
- TEST_SUITE=integration
|
||||
- TEST_SUITE=integration APIURL=http://127.0.0.1:8080/1
|
||||
script: npm run-script $TEST_SUITE
|
||||
|
|
|
@ -16,12 +16,12 @@ const NETWORKS = Object.assign({
|
|||
}
|
||||
}, require('../src/networks'))
|
||||
|
||||
describe('address', function () {
|
||||
describe('fromBase58Check', function () {
|
||||
fixtures.standard.forEach(function (f) {
|
||||
describe('address', () => {
|
||||
describe('fromBase58Check', () => {
|
||||
fixtures.standard.forEach(f => {
|
||||
if (!f.base58check) return
|
||||
|
||||
it('decodes ' + f.base58check, function () {
|
||||
it('decodes ' + f.base58check, () => {
|
||||
const decode = baddress.fromBase58Check(f.base58check)
|
||||
|
||||
assert.strictEqual(decode.version, f.version)
|
||||
|
@ -29,20 +29,20 @@ describe('address', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.fromBase58Check.forEach(function (f) {
|
||||
it('throws on ' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.fromBase58Check.forEach(f => {
|
||||
it('throws on ' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
baddress.fromBase58Check(f.address)
|
||||
}, new RegExp(f.address + ' ' + f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fromBech32', function () {
|
||||
fixtures.standard.forEach((f) => {
|
||||
describe('fromBech32', () => {
|
||||
fixtures.standard.forEach(f => {
|
||||
if (!f.bech32) return
|
||||
|
||||
it('decodes ' + f.bech32, function () {
|
||||
it('decodes ' + f.bech32, () => {
|
||||
const actual = baddress.fromBech32(f.bech32)
|
||||
|
||||
assert.strictEqual(actual.version, f.version)
|
||||
|
@ -52,17 +52,17 @@ describe('address', function () {
|
|||
})
|
||||
|
||||
fixtures.invalid.bech32.forEach((f, i) => {
|
||||
it('decode fails for ' + f.bech32 + '(' + f.exception + ')', function () {
|
||||
assert.throws(function () {
|
||||
it('decode fails for ' + f.bech32 + '(' + f.exception + ')', () => {
|
||||
assert.throws(() => {
|
||||
baddress.fromBech32(f.address)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fromOutputScript', function () {
|
||||
fixtures.standard.forEach(function (f) {
|
||||
it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () {
|
||||
describe('fromOutputScript', () => {
|
||||
fixtures.standard.forEach(f => {
|
||||
it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
|
||||
const script = bscript.fromASM(f.script)
|
||||
const address = baddress.fromOutputScript(script, NETWORKS[f.network])
|
||||
|
||||
|
@ -70,22 +70,22 @@ describe('address', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.fromOutputScript.forEach(function (f) {
|
||||
it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, function () {
|
||||
fixtures.invalid.fromOutputScript.forEach(f => {
|
||||
it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, () => {
|
||||
const script = bscript.fromASM(f.script)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
baddress.fromOutputScript(script)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('toBase58Check', function () {
|
||||
fixtures.standard.forEach(function (f) {
|
||||
describe('toBase58Check', () => {
|
||||
fixtures.standard.forEach(f => {
|
||||
if (!f.base58check) return
|
||||
|
||||
it('encodes ' + f.hash + ' (' + f.network + ')', function () {
|
||||
it('encodes ' + f.hash + ' (' + f.network + ')', () => {
|
||||
const address = baddress.toBase58Check(Buffer.from(f.hash, 'hex'), f.version)
|
||||
|
||||
assert.strictEqual(address, f.base58check)
|
||||
|
@ -93,39 +93,39 @@ describe('address', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('toBech32', function () {
|
||||
describe('toBech32', () => {
|
||||
fixtures.bech32.forEach((f, i) => {
|
||||
if (!f.bech32) return
|
||||
const data = Buffer.from(f.data, 'hex')
|
||||
|
||||
it('encode ' + f.address, function () {
|
||||
assert.deepEqual(baddress.toBech32(data, f.version, f.prefix), f.address)
|
||||
it('encode ' + f.address, () => {
|
||||
assert.deepStrictEqual(baddress.toBech32(data, f.version, f.prefix), f.address)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.bech32.forEach((f, i) => {
|
||||
if (!f.prefix || f.version === undefined || f.data === undefined) return
|
||||
|
||||
it('encode fails (' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
it('encode fails (' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
baddress.toBech32(Buffer.from(f.data, 'hex'), f.version, f.prefix)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('toOutputScript', function () {
|
||||
fixtures.standard.forEach(function (f) {
|
||||
it('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () {
|
||||
describe('toOutputScript', () => {
|
||||
fixtures.standard.forEach(f => {
|
||||
it('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
|
||||
const script = baddress.toOutputScript(f.base58check || f.bech32, NETWORKS[f.network])
|
||||
|
||||
assert.strictEqual(bscript.toASM(script), f.script)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.toOutputScript.forEach(function (f) {
|
||||
it('throws when ' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.toOutputScript.forEach(f => {
|
||||
it('throws when ' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
baddress.toOutputScript(f.address, f.network)
|
||||
}, new RegExp(f.address + ' ' + f.exception))
|
||||
})
|
||||
|
|
|
@ -12,21 +12,21 @@ const sigHash = require('./fixtures/core/sighash.json')
|
|||
const sigNoncanonical = require('./fixtures/core/sig_noncanonical.json')
|
||||
const txValid = require('./fixtures/core/tx_valid.json')
|
||||
|
||||
describe('Bitcoin-core', function () {
|
||||
describe('Bitcoin-core', () => {
|
||||
// base58EncodeDecode
|
||||
describe('base58', function () {
|
||||
base58EncodeDecode.forEach(function (f) {
|
||||
describe('base58', () => {
|
||||
base58EncodeDecode.forEach(f => {
|
||||
const fhex = f[0]
|
||||
const fb58 = f[1]
|
||||
|
||||
it('can decode ' + fb58, function () {
|
||||
it('can decode ' + fb58, () => {
|
||||
const buffer = base58.decode(fb58)
|
||||
const actual = buffer.toString('hex')
|
||||
|
||||
assert.strictEqual(actual, fhex)
|
||||
})
|
||||
|
||||
it('can encode ' + fhex, function () {
|
||||
it('can encode ' + fhex, () => {
|
||||
const buffer = Buffer.from(fhex, 'hex')
|
||||
const actual = base58.encode(buffer)
|
||||
|
||||
|
@ -36,13 +36,13 @@ describe('Bitcoin-core', function () {
|
|||
})
|
||||
|
||||
// base58KeysValid
|
||||
describe('address.toBase58Check', function () {
|
||||
describe('address.toBase58Check', () => {
|
||||
const typeMap = {
|
||||
'pubkey': 'pubKeyHash',
|
||||
'script': 'scriptHash'
|
||||
}
|
||||
|
||||
base58KeysValid.forEach(function (f) {
|
||||
base58KeysValid.forEach(f => {
|
||||
const expected = f[0]
|
||||
const hash = Buffer.from(f[1], 'hex')
|
||||
const params = f[2]
|
||||
|
@ -52,14 +52,14 @@ describe('Bitcoin-core', function () {
|
|||
const network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin
|
||||
const version = network[typeMap[params.addrType]]
|
||||
|
||||
it('can export ' + expected, function () {
|
||||
it('can export ' + expected, () => {
|
||||
assert.strictEqual(bitcoin.address.toBase58Check(hash, version), expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// base58KeysInvalid
|
||||
describe('address.fromBase58Check', function () {
|
||||
describe('address.fromBase58Check', () => {
|
||||
const allowedNetworks = [
|
||||
bitcoin.networks.bitcoin.pubkeyhash,
|
||||
bitcoin.networks.bitcoin.scripthash,
|
||||
|
@ -67,22 +67,22 @@ describe('Bitcoin-core', function () {
|
|||
bitcoin.networks.testnet.scripthash
|
||||
]
|
||||
|
||||
base58KeysInvalid.forEach(function (f) {
|
||||
base58KeysInvalid.forEach(f => {
|
||||
const string = f[0]
|
||||
|
||||
it('throws on ' + string, function () {
|
||||
assert.throws(function () {
|
||||
it('throws on ' + string, () => {
|
||||
assert.throws(() => {
|
||||
const address = bitcoin.address.fromBase58Check(string)
|
||||
|
||||
assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network')
|
||||
assert.notStrictEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network')
|
||||
}, /(Invalid (checksum|network))|(too (short|long))/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// base58KeysValid
|
||||
describe('ECPair', function () {
|
||||
base58KeysValid.forEach(function (f) {
|
||||
describe('ECPair', () => {
|
||||
base58KeysValid.forEach(f => {
|
||||
const string = f[0]
|
||||
const hex = f[1]
|
||||
const params = f[2]
|
||||
|
@ -92,38 +92,38 @@ describe('Bitcoin-core', function () {
|
|||
const network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin
|
||||
const keyPair = bitcoin.ECPair.fromWIF(string, network)
|
||||
|
||||
it('fromWIF imports ' + string, function () {
|
||||
it('fromWIF imports ' + string, () => {
|
||||
assert.strictEqual(keyPair.privateKey.toString('hex'), hex)
|
||||
assert.strictEqual(keyPair.compressed, params.isCompressed)
|
||||
})
|
||||
|
||||
it('toWIF exports ' + hex + ' to ' + string, function () {
|
||||
it('toWIF exports ' + hex + ' to ' + string, () => {
|
||||
assert.strictEqual(keyPair.toWIF(), string)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// base58KeysInvalid
|
||||
describe('ECPair.fromWIF', function () {
|
||||
describe('ECPair.fromWIF', () => {
|
||||
const allowedNetworks = [
|
||||
bitcoin.networks.bitcoin,
|
||||
bitcoin.networks.testnet
|
||||
]
|
||||
|
||||
base58KeysInvalid.forEach(function (f) {
|
||||
base58KeysInvalid.forEach(f => {
|
||||
const string = f[0]
|
||||
|
||||
it('throws on ' + string, function () {
|
||||
assert.throws(function () {
|
||||
it('throws on ' + string, () => {
|
||||
assert.throws(() => {
|
||||
bitcoin.ECPair.fromWIF(string, allowedNetworks)
|
||||
}, /(Invalid|Unknown) (checksum|compression flag|network version|WIF length)/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Block.fromHex', function () {
|
||||
blocksValid.forEach(function (f) {
|
||||
it('can parse ' + f.id, function () {
|
||||
describe('Block.fromHex', () => {
|
||||
blocksValid.forEach(f => {
|
||||
it('can parse ' + f.id, () => {
|
||||
const block = bitcoin.Block.fromHex(f.hex)
|
||||
|
||||
assert.strictEqual(block.getId(), f.id)
|
||||
|
@ -133,8 +133,8 @@ describe('Bitcoin-core', function () {
|
|||
})
|
||||
|
||||
// txValid
|
||||
describe('Transaction.fromHex', function () {
|
||||
txValid.forEach(function (f) {
|
||||
describe('Transaction.fromHex', () => {
|
||||
txValid.forEach(f => {
|
||||
// Objects that are only a single string are ignored
|
||||
if (f.length === 1) return
|
||||
|
||||
|
@ -142,17 +142,17 @@ describe('Bitcoin-core', function () {
|
|||
const fhex = f[1]
|
||||
// const verifyFlags = f[2] // TODO: do we need to test this?
|
||||
|
||||
it('can decode ' + fhex, function () {
|
||||
it('can decode ' + fhex, () => {
|
||||
const transaction = bitcoin.Transaction.fromHex(fhex)
|
||||
|
||||
transaction.ins.forEach(function (txIn, i) {
|
||||
transaction.ins.forEach((txIn, i) => {
|
||||
const input = inputs[i]
|
||||
|
||||
// reverse because test data is reversed
|
||||
const prevOutHash = Buffer.from(input[0], 'hex').reverse()
|
||||
const prevOutIndex = input[1]
|
||||
|
||||
assert.deepEqual(txIn.hash, prevOutHash)
|
||||
assert.deepStrictEqual(txIn.hash, prevOutHash)
|
||||
|
||||
// we read UInt32, not Int32
|
||||
assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex)
|
||||
|
@ -162,8 +162,8 @@ describe('Bitcoin-core', function () {
|
|||
})
|
||||
|
||||
// sighash
|
||||
describe('Transaction', function () {
|
||||
sigHash.forEach(function (f) {
|
||||
describe('Transaction', () => {
|
||||
sigHash.forEach(f => {
|
||||
// Objects that are only a single string are ignored
|
||||
if (f.length === 1) return
|
||||
|
||||
|
@ -181,7 +181,7 @@ describe('Bitcoin-core', function () {
|
|||
|
||||
const hashTypeName = hashTypes.join(' | ')
|
||||
|
||||
it('should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')', function () {
|
||||
it('should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')', () => {
|
||||
const transaction = bitcoin.Transaction.fromHex(txHex)
|
||||
assert.strictEqual(transaction.toHex(), txHex)
|
||||
|
||||
|
@ -192,16 +192,16 @@ describe('Bitcoin-core', function () {
|
|||
const hash = transaction.hashForSignature(inIndex, script, hashType)
|
||||
|
||||
// reverse because test data is reversed
|
||||
assert.equal(hash.reverse().toString('hex'), expectedHash)
|
||||
assert.strictEqual(hash.reverse().toString('hex'), expectedHash)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('script.signature.decode', function () {
|
||||
sigCanonical.forEach(function (hex) {
|
||||
describe('script.signature.decode', () => {
|
||||
sigCanonical.forEach(hex => {
|
||||
const buffer = Buffer.from(hex, 'hex')
|
||||
|
||||
it('can parse ' + hex, function () {
|
||||
it('can parse ' + hex, () => {
|
||||
const parsed = bitcoin.script.signature.decode(buffer)
|
||||
const actual = bitcoin.script.signature.encode(parsed.signature, parsed.hashType)
|
||||
|
||||
|
@ -209,15 +209,15 @@ describe('Bitcoin-core', function () {
|
|||
})
|
||||
})
|
||||
|
||||
sigNoncanonical.forEach(function (hex, i) {
|
||||
sigNoncanonical.forEach((hex, i) => {
|
||||
if (i === 0) return
|
||||
if (i % 2 !== 0) return
|
||||
|
||||
const description = sigNoncanonical[i - 1].slice(0, -1)
|
||||
const buffer = Buffer.from(hex, 'hex')
|
||||
|
||||
it('throws on ' + description, function () {
|
||||
assert.throws(function () {
|
||||
it('throws on ' + description, () => {
|
||||
assert.throws(() => {
|
||||
bitcoin.script.signature.decode(buffer)
|
||||
}, /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/)
|
||||
})
|
||||
|
|
|
@ -4,29 +4,29 @@ const Block = require('..').Block
|
|||
|
||||
const fixtures = require('./fixtures/block')
|
||||
|
||||
describe('Block', function () {
|
||||
describe('version', function () {
|
||||
it('should be interpreted as an int32le', function () {
|
||||
describe('Block', () => {
|
||||
describe('version', () => {
|
||||
it('should be interpreted as an int32le', () => {
|
||||
const blockHex = 'ffffffff0000000000000000000000000000000000000000000000000000000000000000414141414141414141414141414141414141414141414141414141414141414101000000020000000300000000'
|
||||
const block = Block.fromHex(blockHex)
|
||||
assert.equal(-1, block.version)
|
||||
assert.equal(1, block.timestamp)
|
||||
assert.strictEqual(-1, block.version)
|
||||
assert.strictEqual(1, block.timestamp)
|
||||
})
|
||||
})
|
||||
|
||||
describe('calculateTarget', function () {
|
||||
fixtures.targets.forEach(function (f) {
|
||||
it('returns ' + f.expected + ' for 0x' + f.bits, function () {
|
||||
describe('calculateTarget', () => {
|
||||
fixtures.targets.forEach(f => {
|
||||
it('returns ' + f.expected + ' for 0x' + f.bits, () => {
|
||||
const bits = parseInt(f.bits, 16)
|
||||
|
||||
assert.equal(Block.calculateTarget(bits).toString('hex'), f.expected)
|
||||
assert.strictEqual(Block.calculateTarget(bits).toString('hex'), f.expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fromBuffer/fromHex', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('imports ' + f.description, function () {
|
||||
describe('fromBuffer/fromHex', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('imports ' + f.description, () => {
|
||||
const block = Block.fromHex(f.hex)
|
||||
|
||||
assert.strictEqual(block.version, f.version)
|
||||
|
@ -42,54 +42,54 @@ describe('Block', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.forEach(function (f) {
|
||||
it('throws on ' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.forEach(f => {
|
||||
it('throws on ' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
Block.fromHex(f.hex)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('toBuffer/toHex', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('toBuffer/toHex', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
let block
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
block = Block.fromHex(f.hex)
|
||||
})
|
||||
|
||||
it('exports ' + f.description, function () {
|
||||
it('exports ' + f.description, () => {
|
||||
assert.strictEqual(block.toHex(true), f.hex.slice(0, 160))
|
||||
assert.strictEqual(block.toHex(), f.hex)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getHash/getId', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('getHash/getId', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
let block
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
block = Block.fromHex(f.hex)
|
||||
})
|
||||
|
||||
it('returns ' + f.id + ' for ' + f.description, function () {
|
||||
it('returns ' + f.id + ' for ' + f.description, () => {
|
||||
assert.strictEqual(block.getHash().toString('hex'), f.hash)
|
||||
assert.strictEqual(block.getId(), f.id)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getUTCDate', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('getUTCDate', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
let block
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
block = Block.fromHex(f.hex)
|
||||
})
|
||||
|
||||
it('returns UTC date of ' + f.id, function () {
|
||||
it('returns UTC date of ' + f.id, () => {
|
||||
const utcDate = block.getUTCDate().getTime()
|
||||
|
||||
assert.strictEqual(utcDate, f.timestamp * 1e3)
|
||||
|
@ -97,59 +97,59 @@ describe('Block', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('calculateMerkleRoot', function () {
|
||||
it('should throw on zero-length transaction array', function () {
|
||||
assert.throws(function () {
|
||||
describe('calculateMerkleRoot', () => {
|
||||
it('should throw on zero-length transaction array', () => {
|
||||
assert.throws(() => {
|
||||
Block.calculateMerkleRoot([])
|
||||
}, /Cannot compute merkle root for zero transactions/)
|
||||
})
|
||||
|
||||
fixtures.valid.forEach(function (f) {
|
||||
fixtures.valid.forEach(f => {
|
||||
if (f.hex.length === 160) return
|
||||
|
||||
let block
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
block = Block.fromHex(f.hex)
|
||||
})
|
||||
|
||||
it('returns ' + f.merkleRoot + ' for ' + f.id, function () {
|
||||
it('returns ' + f.merkleRoot + ' for ' + f.id, () => {
|
||||
assert.strictEqual(Block.calculateMerkleRoot(block.transactions).toString('hex'), f.merkleRoot)
|
||||
})
|
||||
|
||||
if (f.witnessCommit) {
|
||||
it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, function () {
|
||||
it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, () => {
|
||||
assert.strictEqual(Block.calculateMerkleRoot(block.transactions, true).toString('hex'), f.witnessCommit)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('checkTxRoots', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('checkTxRoots', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
if (f.hex.length === 160) return
|
||||
|
||||
let block
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
block = Block.fromHex(f.hex)
|
||||
})
|
||||
|
||||
it('returns ' + f.valid + ' for ' + f.id, function () {
|
||||
it('returns ' + f.valid + ' for ' + f.id, () => {
|
||||
assert.strictEqual(block.checkTxRoots(), true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('checkProofOfWork', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('checkProofOfWork', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
let block
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
block = Block.fromHex(f.hex)
|
||||
})
|
||||
|
||||
it('returns ' + f.valid + ' for ' + f.id, function () {
|
||||
it('returns ' + f.valid + ' for ' + f.id, () => {
|
||||
assert.strictEqual(block.checkProofOfWork(), f.valid)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,10 +4,10 @@ const bufferutils = require('../src/bufferutils')
|
|||
|
||||
const fixtures = require('./fixtures/bufferutils.json')
|
||||
|
||||
describe('bufferutils', function () {
|
||||
describe('readUInt64LE', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('decodes ' + f.hex, function () {
|
||||
describe('bufferutils', () => {
|
||||
describe('readUInt64LE', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('decodes ' + f.hex, () => {
|
||||
const buffer = Buffer.from(f.hex, 'hex')
|
||||
const number = bufferutils.readUInt64LE(buffer, 0)
|
||||
|
||||
|
@ -15,20 +15,20 @@ describe('bufferutils', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.readUInt64LE.forEach(function (f) {
|
||||
it('throws on ' + f.description, function () {
|
||||
fixtures.invalid.readUInt64LE.forEach(f => {
|
||||
it('throws on ' + f.description, () => {
|
||||
const buffer = Buffer.from(f.hex, 'hex')
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
bufferutils.readUInt64LE(buffer, 0)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('writeUInt64LE', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('encodes ' + f.dec, function () {
|
||||
describe('writeUInt64LE', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('encodes ' + f.dec, () => {
|
||||
const buffer = Buffer.alloc(8, 0)
|
||||
|
||||
bufferutils.writeUInt64LE(buffer, f.dec, 0)
|
||||
|
@ -36,11 +36,11 @@ describe('bufferutils', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.readUInt64LE.forEach(function (f) {
|
||||
it('throws on ' + f.description, function () {
|
||||
fixtures.invalid.readUInt64LE.forEach(f => {
|
||||
it('throws on ' + f.description, () => {
|
||||
const buffer = Buffer.alloc(8, 0)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
bufferutils.writeUInt64LE(buffer, f.dec, 0)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
|
|
|
@ -25,12 +25,12 @@ const tmap = {
|
|||
witnessCommitment
|
||||
}
|
||||
|
||||
describe('classify', function () {
|
||||
describe('input', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('classify', () => {
|
||||
describe('input', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
if (!f.input) return
|
||||
|
||||
it('classifies ' + f.input + ' as ' + f.type, function () {
|
||||
it('classifies ' + f.input + ' as ' + f.type, () => {
|
||||
const input = bscript.fromASM(f.input)
|
||||
const type = classify.input(input)
|
||||
|
||||
|
@ -38,11 +38,11 @@ describe('classify', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.valid.forEach(function (f) {
|
||||
fixtures.valid.forEach(f => {
|
||||
if (!f.input) return
|
||||
if (!f.typeIncomplete) return
|
||||
|
||||
it('classifies incomplete ' + f.input + ' as ' + f.typeIncomplete, function () {
|
||||
it('classifies incomplete ' + f.input + ' as ' + f.typeIncomplete, () => {
|
||||
const input = bscript.fromASM(f.input)
|
||||
const type = classify.input(input, true)
|
||||
|
||||
|
@ -51,11 +51,11 @@ describe('classify', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('classifyOutput', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('classifyOutput', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
if (!f.output) return
|
||||
|
||||
it('classifies ' + f.output + ' as ' + f.type, function () {
|
||||
it('classifies ' + f.output + ' as ' + f.type, () => {
|
||||
const output = bscript.fromASM(f.output)
|
||||
const type = classify.output(output)
|
||||
|
||||
|
@ -73,12 +73,12 @@ describe('classify', function () {
|
|||
'multisig',
|
||||
'nullData',
|
||||
'witnessCommitment'
|
||||
].forEach(function (name) {
|
||||
].forEach(name => {
|
||||
const inputType = tmap[name].input
|
||||
const outputType = tmap[name].output
|
||||
|
||||
describe(name + '.input.check', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe(name + '.input.check', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
if (name.toLowerCase() === classify.types.P2WPKH) return
|
||||
if (name.toLowerCase() === classify.types.P2WSH) return
|
||||
const expected = name.toLowerCase() === f.type.toLowerCase()
|
||||
|
@ -86,14 +86,14 @@ describe('classify', function () {
|
|||
if (inputType && f.input) {
|
||||
const input = bscript.fromASM(f.input)
|
||||
|
||||
it('returns ' + expected + ' for ' + f.input, function () {
|
||||
it('returns ' + expected + ' for ' + f.input, () => {
|
||||
assert.strictEqual(inputType.check(input), expected)
|
||||
})
|
||||
|
||||
if (f.typeIncomplete) {
|
||||
const expectedIncomplete = name.toLowerCase() === f.typeIncomplete
|
||||
|
||||
it('returns ' + expected + ' for ' + f.input, function () {
|
||||
it('returns ' + expected + ' for ' + f.input, () => {
|
||||
assert.strictEqual(inputType.check(input, true), expectedIncomplete)
|
||||
})
|
||||
}
|
||||
|
@ -102,10 +102,10 @@ describe('classify', function () {
|
|||
|
||||
if (!(fixtures.invalid[name])) return
|
||||
|
||||
fixtures.invalid[name].inputs.forEach(function (f) {
|
||||
fixtures.invalid[name].inputs.forEach(f => {
|
||||
if (!f.input && !f.inputHex) return
|
||||
|
||||
it('returns false for ' + f.description + ' (' + (f.input || f.inputHex) + ')', function () {
|
||||
it('returns false for ' + f.description + ' (' + (f.input || f.inputHex) + ')', () => {
|
||||
let input
|
||||
|
||||
if (f.input) {
|
||||
|
@ -119,12 +119,12 @@ describe('classify', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe(name + '.output.check', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe(name + '.output.check', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
const expected = name.toLowerCase() === f.type
|
||||
|
||||
if (outputType && f.output) {
|
||||
it('returns ' + expected + ' for ' + f.output, function () {
|
||||
it('returns ' + expected + ' for ' + f.output, () => {
|
||||
const output = bscript.fromASM(f.output)
|
||||
|
||||
if (name.toLowerCase() === 'nulldata' && f.type === classify.types.WITNESS_COMMITMENT) return
|
||||
|
@ -136,10 +136,10 @@ describe('classify', function () {
|
|||
|
||||
if (!(fixtures.invalid[name])) return
|
||||
|
||||
fixtures.invalid[name].outputs.forEach(function (f) {
|
||||
fixtures.invalid[name].outputs.forEach(f => {
|
||||
if (!f.output && !f.outputHex) return
|
||||
|
||||
it('returns false for ' + f.description + ' (' + (f.output || f.outputHex) + ')', function () {
|
||||
it('returns false for ' + f.description + ' (' + (f.output || f.outputHex) + ')', () => {
|
||||
let output
|
||||
|
||||
if (f.output) {
|
||||
|
|
|
@ -4,14 +4,14 @@ const bcrypto = require('../src/crypto')
|
|||
|
||||
const fixtures = require('./fixtures/crypto')
|
||||
|
||||
describe('crypto', function () {
|
||||
['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(function (algorithm) {
|
||||
describe(algorithm, function () {
|
||||
fixtures.forEach(function (f) {
|
||||
describe('crypto', () => {
|
||||
['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => {
|
||||
describe(algorithm, () => {
|
||||
fixtures.forEach(f => {
|
||||
const fn = bcrypto[algorithm]
|
||||
const expected = f[algorithm]
|
||||
|
||||
it('returns ' + expected + ' for ' + f.hex, function () {
|
||||
it('returns ' + expected + ' for ' + f.hex, () => {
|
||||
const data = Buffer.from(f.hex, 'hex')
|
||||
const actual = fn(data).toString('hex')
|
||||
|
||||
|
|
102
test/ecpair.js
102
test/ecpair.js
|
@ -19,15 +19,15 @@ const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000
|
|||
const GROUP_ORDER = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex')
|
||||
const GROUP_ORDER_LESS_1 = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', 'hex')
|
||||
|
||||
describe('ECPair', function () {
|
||||
describe('getPublicKey', function () {
|
||||
describe('ECPair', () => {
|
||||
describe('getPublicKey', () => {
|
||||
let keyPair
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
keyPair = ECPair.fromPrivateKey(ONE)
|
||||
})
|
||||
|
||||
it('calls pointFromScalar lazily', hoodwink(function () {
|
||||
it('calls pointFromScalar lazily', hoodwink(() => {
|
||||
assert.strictEqual(keyPair.__Q, undefined)
|
||||
|
||||
// .publicKey forces the memoization
|
||||
|
@ -36,14 +36,14 @@ describe('ECPair', function () {
|
|||
}))
|
||||
})
|
||||
|
||||
describe('fromPrivateKey', function () {
|
||||
it('defaults to compressed', function () {
|
||||
describe('fromPrivateKey', () => {
|
||||
it('defaults to compressed', () => {
|
||||
const keyPair = ECPair.fromPrivateKey(ONE)
|
||||
|
||||
assert.strictEqual(keyPair.compressed, true)
|
||||
})
|
||||
|
||||
it('supports the uncompressed option', function () {
|
||||
it('supports the uncompressed option', () => {
|
||||
const keyPair = ECPair.fromPrivateKey(ONE, {
|
||||
compressed: false
|
||||
})
|
||||
|
@ -51,7 +51,7 @@ describe('ECPair', function () {
|
|||
assert.strictEqual(keyPair.compressed, false)
|
||||
})
|
||||
|
||||
it('supports the network option', function () {
|
||||
it('supports the network option', () => {
|
||||
const keyPair = ECPair.fromPrivateKey(ONE, {
|
||||
compressed: false,
|
||||
network: NETWORKS.testnet
|
||||
|
@ -60,8 +60,8 @@ describe('ECPair', function () {
|
|||
assert.strictEqual(keyPair.network, NETWORKS.testnet)
|
||||
})
|
||||
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('derives public key for ' + f.WIF, function () {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('derives public key for ' + f.WIF, () => {
|
||||
const d = Buffer.from(f.d, 'hex')
|
||||
const keyPair = ECPair.fromPrivateKey(d, {
|
||||
compressed: f.compressed
|
||||
|
@ -71,30 +71,30 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.fromPrivateKey.forEach(function (f) {
|
||||
it('throws ' + f.exception, function () {
|
||||
fixtures.invalid.fromPrivateKey.forEach(f => {
|
||||
it('throws ' + f.exception, () => {
|
||||
const d = Buffer.from(f.d, 'hex')
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
ECPair.fromPrivateKey(d, f.options)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fromPublicKey', function () {
|
||||
fixtures.invalid.fromPublicKey.forEach(function (f) {
|
||||
it('throws ' + f.exception, function () {
|
||||
describe('fromPublicKey', () => {
|
||||
fixtures.invalid.fromPublicKey.forEach(f => {
|
||||
it('throws ' + f.exception, () => {
|
||||
const Q = Buffer.from(f.Q, 'hex')
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
ECPair.fromPublicKey(Q, f.options)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fromWIF', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('imports ' + f.WIF + ' (' + f.network + ')', function () {
|
||||
describe('fromWIF', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('imports ' + f.WIF + ' (' + f.network + ')', () => {
|
||||
const network = NETWORKS[f.network]
|
||||
const keyPair = ECPair.fromWIF(f.WIF, network)
|
||||
|
||||
|
@ -104,8 +104,8 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('imports ' + f.WIF + ' (via list of networks)', function () {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('imports ' + f.WIF + ' (via list of networks)', () => {
|
||||
const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
|
||||
|
||||
assert.strictEqual(keyPair.privateKey.toString('hex'), f.d)
|
||||
|
@ -114,9 +114,9 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.fromWIF.forEach(function (f) {
|
||||
it('throws on ' + f.WIF, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.fromWIF.forEach(f => {
|
||||
it('throws on ' + f.WIF, () => {
|
||||
assert.throws(() => {
|
||||
const networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
|
||||
|
||||
ECPair.fromWIF(f.WIF, networks)
|
||||
|
@ -125,9 +125,9 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('toWIF', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('exports ' + f.WIF, function () {
|
||||
describe('toWIF', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('exports ' + f.WIF, () => {
|
||||
const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
|
||||
const result = keyPair.toWIF()
|
||||
assert.strictEqual(result, f.WIF)
|
||||
|
@ -135,13 +135,13 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('makeRandom', function () {
|
||||
describe('makeRandom', () => {
|
||||
const d = Buffer.alloc(32, 4)
|
||||
const exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
|
||||
|
||||
describe('uses randombytes RNG', function () {
|
||||
it('generates a ECPair', function () {
|
||||
const stub = { randombytes: function () { return d } }
|
||||
describe('uses randombytes RNG', () => {
|
||||
it('generates a ECPair', () => {
|
||||
const stub = { randombytes: () => { return d } }
|
||||
const ProxiedECPair = proxyquire('../src/ecpair', stub)
|
||||
|
||||
const keyPair = ProxiedECPair.makeRandom()
|
||||
|
@ -149,22 +149,22 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
it('allows a custom RNG to be used', function () {
|
||||
it('allows a custom RNG to be used', () => {
|
||||
const keyPair = ECPair.makeRandom({
|
||||
rng: function (size) { return d.slice(0, size) }
|
||||
rng: size => { return d.slice(0, size) }
|
||||
})
|
||||
|
||||
assert.strictEqual(keyPair.toWIF(), exWIF)
|
||||
})
|
||||
|
||||
it('retains the same defaults as ECPair constructor', function () {
|
||||
it('retains the same defaults as ECPair constructor', () => {
|
||||
const keyPair = ECPair.makeRandom()
|
||||
|
||||
assert.strictEqual(keyPair.compressed, true)
|
||||
assert.strictEqual(keyPair.network, NETWORKS.bitcoin)
|
||||
})
|
||||
|
||||
it('supports the options parameter', function () {
|
||||
it('supports the options parameter', () => {
|
||||
const keyPair = ECPair.makeRandom({
|
||||
compressed: false,
|
||||
network: NETWORKS.testnet
|
||||
|
@ -174,18 +174,18 @@ describe('ECPair', function () {
|
|||
assert.strictEqual(keyPair.network, NETWORKS.testnet)
|
||||
})
|
||||
|
||||
it('throws if d is bad length', function () {
|
||||
it('throws if d is bad length', () => {
|
||||
function rng () {
|
||||
return Buffer.alloc(28)
|
||||
}
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
ECPair.makeRandom({ rng: rng })
|
||||
}, /Expected Buffer\(Length: 32\), got Buffer\(Length: 28\)/)
|
||||
})
|
||||
|
||||
it('loops until d is within interval [1, n) : 1', hoodwink(function () {
|
||||
const rng = this.stub(function () {
|
||||
const rng = this.stub(() => {
|
||||
if (rng.calls === 0) return ZERO // 0
|
||||
return ONE // >0
|
||||
}, 2)
|
||||
|
@ -194,7 +194,7 @@ describe('ECPair', function () {
|
|||
}))
|
||||
|
||||
it('loops until d is within interval [1, n) : n - 1', hoodwink(function () {
|
||||
const rng = this.stub(function () {
|
||||
const rng = this.stub(() => {
|
||||
if (rng.calls === 0) return ZERO // <1
|
||||
if (rng.calls === 1) return GROUP_ORDER // >n-1
|
||||
return GROUP_ORDER_LESS_1 // n-1
|
||||
|
@ -204,9 +204,9 @@ describe('ECPair', function () {
|
|||
}))
|
||||
})
|
||||
|
||||
describe('.network', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('returns ' + f.network + ' for ' + f.WIF, function () {
|
||||
describe('.network', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('returns ' + f.network + ' for ' + f.WIF, () => {
|
||||
const network = NETWORKS[f.network]
|
||||
const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
|
||||
|
||||
|
@ -215,20 +215,20 @@ describe('ECPair', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('tinysecp wrappers', function () {
|
||||
describe('tinysecp wrappers', () => {
|
||||
let keyPair
|
||||
let hash
|
||||
let signature
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
keyPair = ECPair.makeRandom()
|
||||
hash = ZERO
|
||||
signature = Buffer.alloc(64, 1)
|
||||
})
|
||||
|
||||
describe('signing', function () {
|
||||
describe('signing', () => {
|
||||
it('wraps tinysecp.sign', hoodwink(function () {
|
||||
this.mock(tinysecp, 'sign', function (h, d) {
|
||||
this.mock(tinysecp, 'sign', (h, d) => {
|
||||
assert.strictEqual(h, hash)
|
||||
assert.strictEqual(d, keyPair.privateKey)
|
||||
return signature
|
||||
|
@ -237,18 +237,18 @@ describe('ECPair', function () {
|
|||
assert.strictEqual(keyPair.sign(hash), signature)
|
||||
}))
|
||||
|
||||
it('throws if no private key is found', function () {
|
||||
it('throws if no private key is found', () => {
|
||||
delete keyPair.__D
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
keyPair.sign(hash)
|
||||
}, /Missing private key/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('verify', function () {
|
||||
describe('verify', () => {
|
||||
it('wraps tinysecp.verify', hoodwink(function () {
|
||||
this.mock(tinysecp, 'verify', function (h, q, s) {
|
||||
this.mock(tinysecp, 'verify', (h, q, s) => {
|
||||
assert.strictEqual(h, hash)
|
||||
assert.strictEqual(q, keyPair.publicKey)
|
||||
assert.strictEqual(s, signature)
|
||||
|
|
|
@ -1,99 +1,129 @@
|
|||
const assert = require('assert')
|
||||
const bitcoin = require('../../')
|
||||
const dhttp = require('dhttp/200')
|
||||
const dhttpCallback = require('dhttp/200')
|
||||
// use Promises
|
||||
const dhttp = options => new Promise((resolve, reject) => {
|
||||
return dhttpCallback(options, (err, data) => {
|
||||
if (err) return reject(err)
|
||||
else return resolve(data)
|
||||
})
|
||||
})
|
||||
|
||||
const APIPASS = process.env.APIPASS || 'satoshi'
|
||||
const APIURL = 'https://regtest.bitbank.cc/1'
|
||||
const APIURL = process.env.APIURL || 'https://regtest.bitbank.cc/1'
|
||||
const NETWORK = bitcoin.networks.testnet
|
||||
|
||||
function broadcast (txHex, callback) {
|
||||
dhttp({
|
||||
function broadcast (txHex) {
|
||||
return dhttp({
|
||||
method: 'POST',
|
||||
url: APIURL + '/t/push',
|
||||
body: txHex
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function mine (count, callback) {
|
||||
dhttp({
|
||||
method: 'POST',
|
||||
url: APIURL + '/r/generate?count=' + count + '&key=' + APIPASS
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function height (callback) {
|
||||
dhttp({
|
||||
method: 'GET',
|
||||
url: APIURL + '/b/best/height'
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function faucet (address, value, callback) {
|
||||
dhttp({
|
||||
method: 'POST',
|
||||
url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS
|
||||
}, function (err, txId) {
|
||||
if (err) return callback(err)
|
||||
|
||||
unspents(address, function (err, results) {
|
||||
if (err) return callback(err)
|
||||
|
||||
const unspents = results.filter(x => x.txId === txId)
|
||||
if (unspents.length === 0) return callback(new Error('Missing unspent'))
|
||||
|
||||
callback(null, unspents.pop())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function faucetComplex (output, value, callback) {
|
||||
function mine (count) {
|
||||
return dhttp({
|
||||
method: 'POST',
|
||||
url: APIURL + '/r/generate?count=' + count + '&key=' + APIPASS
|
||||
})
|
||||
}
|
||||
|
||||
function height () {
|
||||
return dhttp({
|
||||
method: 'GET',
|
||||
url: APIURL + '/b/best/height'
|
||||
})
|
||||
}
|
||||
|
||||
function _faucetRequest (address, value) {
|
||||
return dhttp({
|
||||
method: 'POST',
|
||||
url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS
|
||||
})
|
||||
}
|
||||
|
||||
async function faucet (address, value) {
|
||||
let count = 0
|
||||
let _unspents = []
|
||||
const sleep = ms => new Promise((resolve, reject) => setTimeout(resolve, ms))
|
||||
const randInt = (min, max) => min + Math.floor((max - min + 1) * Math.random())
|
||||
while (_unspents.length === 0) {
|
||||
if (count > 0) {
|
||||
if (count >= 5) throw new Error('Missing Inputs')
|
||||
console.log('Missing Inputs, retry #' + count)
|
||||
await sleep(randInt(150, 250))
|
||||
}
|
||||
|
||||
const txId = await _faucetRequest(address, value)
|
||||
.then(
|
||||
v => v, // Pass success value as is
|
||||
async err => {
|
||||
// Bad Request error is fixed by making sure height is >= 432
|
||||
const currentHeight = await height()
|
||||
if (err.message === 'Bad Request' && currentHeight < 432) {
|
||||
await mine(432 - currentHeight)
|
||||
return _faucetRequest(address, value)
|
||||
} else if (err.message === 'Bad Request' && currentHeight >= 432) {
|
||||
return _faucetRequest(address, value)
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await sleep(randInt(10, 40))
|
||||
|
||||
const results = await unspents(address)
|
||||
|
||||
_unspents = results.filter(x => x.txId === txId)
|
||||
|
||||
count++
|
||||
}
|
||||
|
||||
return _unspents.pop()
|
||||
}
|
||||
|
||||
async function faucetComplex (output, value) {
|
||||
const keyPair = bitcoin.ECPair.makeRandom({ network: NETWORK })
|
||||
const p2pkh = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: NETWORK })
|
||||
|
||||
faucet(p2pkh.address, value * 2, (err, unspent) => {
|
||||
if (err) return callback(err)
|
||||
const unspent = await faucet(p2pkh.address, value * 2)
|
||||
|
||||
const txvb = new bitcoin.TransactionBuilder(NETWORK)
|
||||
txvb.addInput(unspent.txId, unspent.vout, null, p2pkh.output)
|
||||
txvb.addOutput(output, value)
|
||||
txvb.sign(0, keyPair)
|
||||
const txv = txvb.build()
|
||||
const txvb = new bitcoin.TransactionBuilder(NETWORK)
|
||||
txvb.addInput(unspent.txId, unspent.vout, null, p2pkh.output)
|
||||
txvb.addOutput(output, value)
|
||||
txvb.sign(0, keyPair)
|
||||
const txv = txvb.build()
|
||||
|
||||
broadcast(txv.toHex(), function (err) {
|
||||
if (err) return callback(err)
|
||||
await broadcast(txv.toHex())
|
||||
|
||||
return callback(null, {
|
||||
txId: txv.getId(),
|
||||
vout: 0,
|
||||
value
|
||||
})
|
||||
})
|
||||
})
|
||||
return {
|
||||
txId: txv.getId(),
|
||||
vout: 0,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
function fetch (txId, callback) {
|
||||
dhttp({
|
||||
function fetch (txId) {
|
||||
return dhttp({
|
||||
method: 'GET',
|
||||
url: APIURL + '/t/' + txId + '/json'
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
function unspents (address, callback) {
|
||||
dhttp({
|
||||
function unspents (address) {
|
||||
return dhttp({
|
||||
method: 'GET',
|
||||
url: APIURL + '/a/' + address + '/unspents'
|
||||
}, callback)
|
||||
})
|
||||
}
|
||||
|
||||
function verify (txo, callback) {
|
||||
fetch(txo.txId, function (err, tx) {
|
||||
if (err) return callback(err)
|
||||
async function verify (txo) {
|
||||
const tx = await fetch(txo.txId)
|
||||
|
||||
const txoActual = tx.outs[txo.vout]
|
||||
if (txo.address) assert.strictEqual(txoActual.address, txo.address)
|
||||
if (txo.value) assert.strictEqual(txoActual.value, txo.value)
|
||||
callback()
|
||||
})
|
||||
const txoActual = tx.outs[txo.vout]
|
||||
if (txo.address) assert.strictEqual(txoActual.address, txo.address)
|
||||
if (txo.value) assert.strictEqual(txoActual.value, txo.value)
|
||||
}
|
||||
|
||||
function getAddress (node, network) {
|
||||
|
@ -108,6 +138,7 @@ function randomAddress () {
|
|||
|
||||
module.exports = {
|
||||
broadcast,
|
||||
dhttp,
|
||||
faucet,
|
||||
faucetComplex,
|
||||
fetch,
|
||||
|
|
|
@ -1,39 +1,36 @@
|
|||
const { describe, it } = require('mocha')
|
||||
const assert = require('assert')
|
||||
const bitcoin = require('../../')
|
||||
const dhttp = require('dhttp/200')
|
||||
const dhttp = require('./_regtest').dhttp
|
||||
const TESTNET = bitcoin.networks.testnet
|
||||
|
||||
describe('bitcoinjs-lib (addresses)', function () {
|
||||
it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', function (done) {
|
||||
describe('bitcoinjs-lib (addresses)', () => {
|
||||
it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', async () => {
|
||||
const keyPair = bitcoin.ECPair.makeRandom()
|
||||
const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey })
|
||||
|
||||
// bitcoin P2PKH addresses start with a '1'
|
||||
assert.strictEqual(address.startsWith('1'), true)
|
||||
|
||||
dhttp({
|
||||
const result = await dhttp({
|
||||
method: 'GET',
|
||||
url: 'https://blockchain.info/rawaddr/' + address
|
||||
}, function (err, result) {
|
||||
if (err) return done(err)
|
||||
|
||||
// random private keys [probably!] have no transactions
|
||||
assert.strictEqual(result.n_tx, 0)
|
||||
assert.strictEqual(result.total_received, 0)
|
||||
assert.strictEqual(result.total_sent, 0)
|
||||
done()
|
||||
})
|
||||
|
||||
// random private keys [probably!] have no transactions
|
||||
assert.strictEqual(result.n_tx, 0)
|
||||
assert.strictEqual(result.total_received, 0)
|
||||
assert.strictEqual(result.total_sent, 0)
|
||||
})
|
||||
|
||||
it('can import an address via WIF', function () {
|
||||
it('can import an address via WIF', () => {
|
||||
const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn')
|
||||
const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey })
|
||||
|
||||
assert.strictEqual(address, '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH')
|
||||
})
|
||||
|
||||
it('can generate a P2SH, pay-to-multisig (2-of-3) address', function () {
|
||||
it('can generate a P2SH, pay-to-multisig (2-of-3) address', () => {
|
||||
const pubkeys = [
|
||||
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
|
||||
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
|
||||
|
@ -46,14 +43,14 @@ describe('bitcoinjs-lib (addresses)', function () {
|
|||
assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
|
||||
})
|
||||
|
||||
it('can generate a SegWit address', function () {
|
||||
it('can generate a SegWit address', () => {
|
||||
const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn')
|
||||
const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey })
|
||||
|
||||
assert.strictEqual(address, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4')
|
||||
})
|
||||
|
||||
it('can generate a SegWit address (via P2SH)', function () {
|
||||
it('can generate a SegWit address (via P2SH)', () => {
|
||||
const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn')
|
||||
const { address } = bitcoin.payments.p2sh({
|
||||
redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey })
|
||||
|
@ -62,7 +59,7 @@ describe('bitcoinjs-lib (addresses)', function () {
|
|||
assert.strictEqual(address, '3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN')
|
||||
})
|
||||
|
||||
it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', function () {
|
||||
it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', () => {
|
||||
const pubkeys = [
|
||||
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
|
||||
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
|
||||
|
@ -76,7 +73,7 @@ describe('bitcoinjs-lib (addresses)', function () {
|
|||
assert.strictEqual(address, 'bc1q75f6dv4q8ug7zhujrsp5t0hzf33lllnr3fe7e2pra3v24mzl8rrqtp3qul')
|
||||
})
|
||||
|
||||
it('can generate a P2SH(P2WSH(...)), pay-to-multisig (2-of-2) address', function () {
|
||||
it('can generate a P2SH(P2WSH(...)), pay-to-multisig (2-of-2) address', () => {
|
||||
const pubkeys = [
|
||||
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
|
||||
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9'
|
||||
|
@ -91,7 +88,7 @@ describe('bitcoinjs-lib (addresses)', function () {
|
|||
})
|
||||
|
||||
// examples using other network information
|
||||
it('can generate a Testnet address', function () {
|
||||
it('can generate a Testnet address', () => {
|
||||
const keyPair = bitcoin.ECPair.makeRandom({ network: TESTNET })
|
||||
const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: TESTNET })
|
||||
|
||||
|
@ -99,7 +96,7 @@ describe('bitcoinjs-lib (addresses)', function () {
|
|||
assert.strictEqual(address.startsWith('m') || address.startsWith('n'), true)
|
||||
})
|
||||
|
||||
it('can generate a Litecoin address', function () {
|
||||
it('can generate a Litecoin address', () => {
|
||||
// WARNING: although possible, bitcoinjs is NOT necessarily compatible with Litecoin
|
||||
const LITECOIN = {
|
||||
messagePrefix: '\x19Litecoin Signed Message:\n',
|
||||
|
|
|
@ -8,35 +8,35 @@ function getAddress (node, network) {
|
|||
return bitcoin.payments.p2pkh({ pubkey: node.publicKey, network }).address
|
||||
}
|
||||
|
||||
describe('bitcoinjs-lib (BIP32)', function () {
|
||||
it('can import a BIP32 testnet xpriv and export to WIF', function () {
|
||||
describe('bitcoinjs-lib (BIP32)', () => {
|
||||
it('can import a BIP32 testnet xpriv and export to WIF', () => {
|
||||
const xpriv = 'tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK'
|
||||
const node = bip32.fromBase58(xpriv, bitcoin.networks.testnet)
|
||||
|
||||
assert.equal(node.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7')
|
||||
assert.strictEqual(node.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7')
|
||||
})
|
||||
|
||||
it('can export a BIP32 xpriv, then import it', function () {
|
||||
it('can export a BIP32 xpriv, then import it', () => {
|
||||
const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
|
||||
const seed = bip39.mnemonicToSeed(mnemonic)
|
||||
const node = bip32.fromSeed(seed)
|
||||
const string = node.toBase58()
|
||||
const restored = bip32.fromBase58(string)
|
||||
|
||||
assert.equal(getAddress(node), getAddress(restored)) // same public key
|
||||
assert.equal(node.toWIF(), restored.toWIF()) // same private key
|
||||
assert.strictEqual(getAddress(node), getAddress(restored)) // same public key
|
||||
assert.strictEqual(node.toWIF(), restored.toWIF()) // same private key
|
||||
})
|
||||
|
||||
it('can export a BIP32 xpub', function () {
|
||||
it('can export a BIP32 xpub', () => {
|
||||
const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
|
||||
const seed = bip39.mnemonicToSeed(mnemonic)
|
||||
const node = bip32.fromSeed(seed)
|
||||
const string = node.neutered().toBase58()
|
||||
|
||||
assert.equal(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n')
|
||||
assert.strictEqual(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n')
|
||||
})
|
||||
|
||||
it('can create a BIP32, bitcoin, account 0, external address', function () {
|
||||
it('can create a BIP32, bitcoin, account 0, external address', () => {
|
||||
const path = "m/0'/0/0"
|
||||
const root = bip32.fromSeed(Buffer.from('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', 'hex'))
|
||||
|
||||
|
@ -47,11 +47,11 @@ describe('bitcoinjs-lib (BIP32)', function () {
|
|||
.derive(0)
|
||||
.derive(0)
|
||||
|
||||
assert.equal(getAddress(child1), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
|
||||
assert.equal(getAddress(child1b), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
|
||||
assert.strictEqual(getAddress(child1), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
|
||||
assert.strictEqual(getAddress(child1b), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
|
||||
})
|
||||
|
||||
it('can create a BIP44, bitcoin, account 0, external address', function () {
|
||||
it('can create a BIP44, bitcoin, account 0, external address', () => {
|
||||
const root = bip32.fromSeed(Buffer.from('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', 'hex'))
|
||||
|
||||
const child1 = root.derivePath("m/44'/0'/0'/0/0")
|
||||
|
@ -63,11 +63,11 @@ describe('bitcoinjs-lib (BIP32)', function () {
|
|||
.derive(0)
|
||||
.derive(0)
|
||||
|
||||
assert.equal(getAddress(child1), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
|
||||
assert.equal(getAddress(child1b), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
|
||||
assert.strictEqual(getAddress(child1), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
|
||||
assert.strictEqual(getAddress(child1b), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
|
||||
})
|
||||
|
||||
it('can create a BIP49, bitcoin testnet, account 0, external address', function () {
|
||||
it('can create a BIP49, bitcoin testnet, account 0, external address', () => {
|
||||
const mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
|
||||
const seed = bip39.mnemonicToSeed(mnemonic)
|
||||
const root = bip32.fromSeed(seed)
|
||||
|
@ -79,10 +79,10 @@ describe('bitcoinjs-lib (BIP32)', function () {
|
|||
redeem: bitcoin.payments.p2wpkh({ pubkey: child.publicKey, network: bitcoin.networks.testnet }),
|
||||
network: bitcoin.networks.testnet
|
||||
})
|
||||
assert.equal(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2')
|
||||
assert.strictEqual(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2')
|
||||
})
|
||||
|
||||
it('can use BIP39 to generate BIP32 addresses', function () {
|
||||
it('can use BIP39 to generate BIP32 addresses', () => {
|
||||
// var mnemonic = bip39.generateMnemonic()
|
||||
const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
|
||||
assert(bip39.validateMnemonic(mnemonic))
|
||||
|
|
|
@ -4,8 +4,8 @@ const { describe, it } = require('mocha')
|
|||
const assert = require('assert')
|
||||
const bitcoin = require('../../')
|
||||
|
||||
describe('bitcoinjs-lib (blocks)', function () {
|
||||
it('can extract a height from a CoinBase transaction', function () {
|
||||
describe('bitcoinjs-lib (blocks)', () => {
|
||||
it('can extract a height from a CoinBase transaction', () => {
|
||||
// from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6
|
||||
const txHex = '010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98fd16761d220400000000000000aa340000d49f0000ffffffff02b07fc366000000001976a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12bf1e400120000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
const tx = bitcoin.Transaction.fromHex(txHex)
|
||||
|
|
|
@ -8,10 +8,10 @@ const bip65 = require('bip65')
|
|||
const alice = bitcoin.ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest)
|
||||
const bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest)
|
||||
|
||||
describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
|
||||
describe('bitcoinjs-lib (transactions w/ CLTV)', () => {
|
||||
// force update MTP
|
||||
before(function (done) {
|
||||
regtestUtils.mine(11, done)
|
||||
before(async () => {
|
||||
await regtestUtils.mine(11)
|
||||
})
|
||||
|
||||
const hashType = bitcoin.Transaction.SIGHASH_ALL
|
||||
|
@ -38,188 +38,160 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
|
|||
}
|
||||
|
||||
// expiry past, {Alice's signature} OP_TRUE
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', async () => {
|
||||
// 3 hours ago
|
||||
const lockTime = bip65.encode({ utc: utcNow() - (3600 * 3) })
|
||||
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
|
||||
const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest })
|
||||
|
||||
// fund the P2SH(CLTV) address
|
||||
regtestUtils.faucet(address, 1e5, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(address, 1e5)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 7e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 7e4
|
||||
})
|
||||
})
|
||||
|
||||
// expiry will pass, {Alice's signature} OP_TRUE
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', function (done) {
|
||||
regtestUtils.height(function (err, height) {
|
||||
if (err) return done(err)
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async () => {
|
||||
const height = await regtestUtils.height()
|
||||
// 5 blocks from now
|
||||
const lockTime = bip65.encode({ blocks: height + 5 })
|
||||
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
|
||||
const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest })
|
||||
|
||||
// 5 blocks from now
|
||||
const lockTime = bip65.encode({ blocks: height + 5 })
|
||||
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
|
||||
const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest })
|
||||
// fund the P2SH(CLTV) address
|
||||
const unspent = await regtestUtils.faucet(address, 1e5)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
|
||||
|
||||
// fund the P2SH(CLTV) address
|
||||
regtestUtils.faucet(address, 1e5, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
|
||||
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
// TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
|
||||
// ...
|
||||
// into the future!
|
||||
regtestUtils.mine(5, function (err) {
|
||||
if (err) return done(err)
|
||||
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 7e4
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
// TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
|
||||
// ...
|
||||
// into the future!
|
||||
await regtestUtils.mine(5)
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 7e4
|
||||
})
|
||||
})
|
||||
|
||||
// expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', async () => {
|
||||
// two hours ago
|
||||
const lockTime = bip65.encode({ utc: utcNow() - (3600 * 2) })
|
||||
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
|
||||
const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest })
|
||||
|
||||
// fund the P2SH(CLTV) address
|
||||
regtestUtils.faucet(address, 2e5, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(address, 2e5)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 8e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 8e4)
|
||||
// {Alice's signature} {Bob's signature} OP_FALSE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_FALSE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
// {Alice's signature} {Bob's signature} OP_FALSE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_FALSE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 8e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 8e4
|
||||
})
|
||||
})
|
||||
|
||||
// expiry in the future, {Alice's signature} OP_TRUE
|
||||
it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', function (done) {
|
||||
it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async () => {
|
||||
// two hours from now
|
||||
const lockTime = bip65.encode({ utc: utcNow() + (3600 * 2) })
|
||||
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
|
||||
const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest })
|
||||
|
||||
// fund the P2SH(CLTV) address
|
||||
regtestUtils.faucet(address, 2e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(address, 2e4)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.setLockTime(lockTime)
|
||||
// Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
|
||||
txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, redeemScript, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
]),
|
||||
output: redeemScript
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
assert.throws(function () {
|
||||
if (err) throw err
|
||||
}, /Error: non-final \(code 64\)/)
|
||||
|
||||
done()
|
||||
})
|
||||
await regtestUtils.broadcast(tx.toHex()).catch(err => {
|
||||
assert.throws(() => {
|
||||
if (err) throw err
|
||||
}, /Error: non-final \(code 64\)/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,10 +8,10 @@ const bip68 = require('bip68')
|
|||
const alice = bitcoin.ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest)
|
||||
const bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest)
|
||||
|
||||
describe('bitcoinjs-lib (transactions w/ CSV)', function () {
|
||||
describe('bitcoinjs-lib (transactions w/ CSV)', () => {
|
||||
// force update MTP
|
||||
before(function (done) {
|
||||
regtestUtils.mine(11, done)
|
||||
before(async () => {
|
||||
await regtestUtils.mine(11)
|
||||
})
|
||||
|
||||
const hashType = bitcoin.Transaction.SIGHASH_ALL
|
||||
|
@ -35,66 +35,56 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () {
|
|||
}
|
||||
|
||||
// expiry will pass, {Alice's signature} OP_TRUE
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', function (done) {
|
||||
regtestUtils.height(function (err, height) {
|
||||
if (err) return done(err)
|
||||
it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async () => {
|
||||
// 5 blocks from now
|
||||
const sequence = bip68.encode({ blocks: 5 })
|
||||
const p2sh = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
output: csvCheckSigOutput(alice, bob, sequence)
|
||||
},
|
||||
network: regtest
|
||||
})
|
||||
|
||||
// 5 blocks from now
|
||||
const sequence = bip68.encode({ blocks: 5 })
|
||||
const p2sh = bitcoin.payments.p2sh({
|
||||
redeem: {
|
||||
output: csvCheckSigOutput(alice, bob, sequence)
|
||||
},
|
||||
network: regtest
|
||||
})
|
||||
// fund the P2SH(CSV) address
|
||||
const unspent = await regtestUtils.faucet(p2sh.address, 1e5)
|
||||
|
||||
// fund the P2SH(CSV) address
|
||||
regtestUtils.faucet(p2sh.address, 1e5, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, sequence)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, sequence)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
network: regtest,
|
||||
redeem: {
|
||||
network: regtest,
|
||||
output: p2sh.redeem.output,
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
])
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
network: regtest,
|
||||
redeem: {
|
||||
network: regtest,
|
||||
output: p2sh.redeem.output,
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
])
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
// TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
|
||||
// ...
|
||||
// into the future!
|
||||
await regtestUtils.mine(10)
|
||||
|
||||
// TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
|
||||
// ...
|
||||
// into the future!
|
||||
regtestUtils.mine(10, function (err) {
|
||||
if (err) return done(err)
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 7e4
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 7e4
|
||||
})
|
||||
})
|
||||
|
||||
// expiry in the future, {Alice's signature} OP_TRUE
|
||||
it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', function (done) {
|
||||
it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async () => {
|
||||
// two hours after confirmation
|
||||
const sequence = bip68.encode({ seconds: 7168 })
|
||||
const p2sh = bitcoin.payments.p2sh({
|
||||
|
@ -105,37 +95,33 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () {
|
|||
})
|
||||
|
||||
// fund the P2SH(CSV) address
|
||||
regtestUtils.faucet(p2sh.address, 2e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(p2sh.address, 2e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, sequence)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, sequence)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
|
||||
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
// {Alice's signature} OP_TRUE
|
||||
const tx = txb.buildIncomplete()
|
||||
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType)
|
||||
const redeemScriptSig = bitcoin.payments.p2sh({
|
||||
network: regtest,
|
||||
redeem: {
|
||||
network: regtest,
|
||||
redeem: {
|
||||
network: regtest,
|
||||
output: p2sh.redeem.output,
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
])
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
output: p2sh.redeem.output,
|
||||
input: bitcoin.script.compile([
|
||||
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
||||
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
||||
bitcoin.opcodes.OP_TRUE
|
||||
])
|
||||
}
|
||||
}).input
|
||||
tx.setInputScript(0, redeemScriptSig)
|
||||
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
assert.throws(function () {
|
||||
if (err) throw err
|
||||
}, /Error: non-BIP68-final \(code 64\)/)
|
||||
|
||||
done()
|
||||
})
|
||||
await regtestUtils.broadcast(tx.toHex()).catch(err => {
|
||||
assert.throws(() => {
|
||||
if (err) throw err
|
||||
}, /Error: non-BIP68-final \(code 64\)/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,27 +8,25 @@ const keyPairs = [
|
|||
bitcoin.ECPair.makeRandom({ network: NETWORK })
|
||||
]
|
||||
|
||||
function buildAndSign (depends, prevOutput, redeemScript, witnessScript, done) {
|
||||
regtestUtils.faucetComplex(prevOutput, 5e4, (err, unspent) => {
|
||||
if (err) return done(err)
|
||||
async function buildAndSign (depends, prevOutput, redeemScript, witnessScript) {
|
||||
const unspent = await regtestUtils.faucetComplex(prevOutput, 5e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(NETWORK)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, prevOutput)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
const txb = new bitcoin.TransactionBuilder(NETWORK)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, prevOutput)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
|
||||
if (depends.signatures) {
|
||||
keyPairs.forEach((keyPair) => {
|
||||
txb.sign(0, keyPair, redeemScript, null, unspent.value, witnessScript)
|
||||
})
|
||||
} else if (depends.signature) {
|
||||
txb.sign(0, keyPairs[0], redeemScript, null, unspent.value, witnessScript)
|
||||
}
|
||||
if (depends.signatures) {
|
||||
keyPairs.forEach(keyPair => {
|
||||
txb.sign(0, keyPair, redeemScript, null, unspent.value, witnessScript)
|
||||
})
|
||||
} else if (depends.signature) {
|
||||
txb.sign(0, keyPairs[0], redeemScript, null, unspent.value, witnessScript)
|
||||
}
|
||||
|
||||
regtestUtils.broadcast(txb.build().toHex(), done)
|
||||
})
|
||||
return regtestUtils.broadcast(txb.build().toHex())
|
||||
}
|
||||
|
||||
;['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach((k) => {
|
||||
;['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach(k => {
|
||||
const fixtures = require('../fixtures/' + k)
|
||||
const { depends } = fixtures.dynamic
|
||||
const fn = bitcoin.payments[k]
|
||||
|
@ -41,29 +39,29 @@ function buildAndSign (depends, prevOutput, redeemScript, witnessScript, done) {
|
|||
const { output } = fn(base)
|
||||
if (!output) throw new TypeError('Missing output')
|
||||
|
||||
describe('bitcoinjs-lib (payments - ' + k + ')', function () {
|
||||
it('can broadcast as an output, and be spent as an input', (done) => {
|
||||
buildAndSign(depends, output, null, null, done)
|
||||
describe('bitcoinjs-lib (payments - ' + k + ')', () => {
|
||||
it('can broadcast as an output, and be spent as an input', async () => {
|
||||
await buildAndSign(depends, output, null, null)
|
||||
})
|
||||
|
||||
it('can (as P2SH(' + k + ')) broadcast as an output, and be spent as an input', (done) => {
|
||||
it('can (as P2SH(' + k + ')) broadcast as an output, and be spent as an input', async () => {
|
||||
const p2sh = bitcoin.payments.p2sh({ redeem: { output }, network: NETWORK })
|
||||
buildAndSign(depends, p2sh.output, p2sh.redeem.output, null, done)
|
||||
await buildAndSign(depends, p2sh.output, p2sh.redeem.output, null)
|
||||
})
|
||||
|
||||
// NOTE: P2WPKH cannot be wrapped in P2WSH, consensus fail
|
||||
if (k === 'p2wpkh') return
|
||||
|
||||
it('can (as P2WSH(' + k + ')) broadcast as an output, and be spent as an input', (done) => {
|
||||
it('can (as P2WSH(' + k + ')) broadcast as an output, and be spent as an input', async () => {
|
||||
const p2wsh = bitcoin.payments.p2wsh({ redeem: { output }, network: NETWORK })
|
||||
buildAndSign(depends, p2wsh.output, null, p2wsh.redeem.output, done)
|
||||
await buildAndSign(depends, p2wsh.output, null, p2wsh.redeem.output)
|
||||
})
|
||||
|
||||
it('can (as P2SH(P2WSH(' + k + '))) broadcast as an output, and be spent as an input', (done) => {
|
||||
it('can (as P2SH(P2WSH(' + k + '))) broadcast as an output, and be spent as an input', async () => {
|
||||
const p2wsh = bitcoin.payments.p2wsh({ redeem: { output }, network: NETWORK })
|
||||
const p2sh = bitcoin.payments.p2sh({ redeem: { output: p2wsh.output }, network: NETWORK })
|
||||
|
||||
buildAndSign(depends, p2sh.output, p2sh.redeem.output, p2wsh.redeem.output, done)
|
||||
await buildAndSign(depends, p2sh.output, p2sh.redeem.output, p2wsh.redeem.output)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,8 +8,8 @@ function rng () {
|
|||
return Buffer.from('YT8dAtK4d16A3P1z+TpwB2jJ4aFH3g9M1EioIBkLEV4=', 'base64')
|
||||
}
|
||||
|
||||
describe('bitcoinjs-lib (transactions)', function () {
|
||||
it('can create a 1-to-1 Transaction', function () {
|
||||
describe('bitcoinjs-lib (transactions)', () => {
|
||||
it('can create a 1-to-1 Transaction', () => {
|
||||
const alice = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
|
||||
const txb = new bitcoin.TransactionBuilder()
|
||||
|
||||
|
@ -24,7 +24,7 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
assert.strictEqual(txb.build().toHex(), '01000000019d344070eac3fe6e394a16d06d7704a7d5c0a10eb2a2c16bc98842b7cc20d561000000006b48304502210088828c0bdfcdca68d8ae0caeb6ec62cd3fd5f9b2191848edae33feb533df35d302202e0beadd35e17e7f83a733f5277028a9b453d525553e3f5d2d7a7aa8010a81d60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e02e0000000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00000000')
|
||||
})
|
||||
|
||||
it('can create a 2-to-2 Transaction', function () {
|
||||
it('can create a 2-to-2 Transaction', () => {
|
||||
const alice = bitcoin.ECPair.fromWIF('L1Knwj9W3qK3qMKdTvmg3VfzUs3ij2LETTFhxza9LfD5dngnoLG1')
|
||||
const bob = bitcoin.ECPair.fromWIF('KwcN2pT3wnRAurhy7qMczzbkpY5nXMW2ubh696UBc1bcwctTx26z')
|
||||
|
||||
|
@ -43,7 +43,7 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
assert.strictEqual(txb.build().toHex(), '01000000024c94e48a870b85f41228d33cf25213dfcc8dd796e7211ed6b1f9a014809dbbb5060000006a473044022041450c258ce7cac7da97316bf2ea1ce66d88967c4df94f3e91f4c2a30f5d08cb02203674d516e6bb2b0afd084c3551614bd9cec3c2945231245e891b145f2d6951f0012103e05ce435e462ec503143305feb6c00e06a3ad52fbf939e85c65f3a765bb7baacffffffff3077d9de049574c3af9bc9c09a7c9db80f2d94caaf63988c9166249b955e867d000000006b483045022100aeb5f1332c79c446d3f906e4499b2e678500580a3f90329edf1ba502eec9402e022072c8b863f8c8d6c26f4c691ac9a6610aa4200edc697306648ee844cfbc089d7a012103df7940ee7cddd2f97763f67e1fb13488da3fbdd7f9c68ec5ef0864074745a289ffffffff0220bf0200000000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac10980200000000001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000')
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a typical Transaction', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a typical Transaction', async () => {
|
||||
const alice1 = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||
const alice2 = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||
const aliceChange = bitcoin.ECPair.makeRandom({ network: regtest, rng: rng })
|
||||
|
@ -53,51 +53,45 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
const aliceCpkh = bitcoin.payments.p2pkh({ pubkey: aliceChange.publicKey, network: regtest })
|
||||
|
||||
// give Alice 2 unspent outputs
|
||||
regtestUtils.faucet(alice1pkh.address, 5e4, function (err, unspent0) {
|
||||
if (err) return done(err)
|
||||
const unspent0 = await regtestUtils.faucet(alice1pkh.address, 5e4)
|
||||
|
||||
regtestUtils.faucet(alice2pkh.address, 7e4, function (err, unspent1) {
|
||||
if (err) return done(err)
|
||||
const unspent1 = await regtestUtils.faucet(alice2pkh.address, 7e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent0.txId, unspent0.vout) // alice1 unspent
|
||||
txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent
|
||||
txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend"
|
||||
txb.addOutput(aliceCpkh.address, 1e4) // Alice's change
|
||||
// (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent0.txId, unspent0.vout) // alice1 unspent
|
||||
txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent
|
||||
txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend"
|
||||
txb.addOutput(aliceCpkh.address, 1e4) // Alice's change
|
||||
// (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee
|
||||
|
||||
// Alice signs each input with the respective private keys
|
||||
txb.sign(0, alice1)
|
||||
txb.sign(1, alice2)
|
||||
// Alice signs each input with the respective private keys
|
||||
txb.sign(0, alice1)
|
||||
txb.sign(1, alice2)
|
||||
|
||||
// build and broadcast our RegTest network
|
||||
regtestUtils.broadcast(txb.build().toHex(), done)
|
||||
// to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839
|
||||
})
|
||||
})
|
||||
// build and broadcast our RegTest network
|
||||
await regtestUtils.broadcast(txb.build().toHex())
|
||||
// to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', async () => {
|
||||
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||
const p2pkh = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: regtest })
|
||||
|
||||
regtestUtils.faucet(p2pkh.address, 2e5, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(p2pkh.address, 2e5)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
const data = Buffer.from('bitcoinjs-lib', 'utf8')
|
||||
const embed = bitcoin.payments.embed({ data: [data] })
|
||||
txb.addInput(unspent.txId, unspent.vout)
|
||||
txb.addOutput(embed.output, 1000)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e5)
|
||||
txb.sign(0, keyPair)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
const data = Buffer.from('bitcoinjs-lib', 'utf8')
|
||||
const embed = bitcoin.payments.embed({ data: [data] })
|
||||
txb.addInput(unspent.txId, unspent.vout)
|
||||
txb.addOutput(embed.output, 1000)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e5)
|
||||
txb.sign(0, keyPair)
|
||||
|
||||
// build and broadcast to the RegTest network
|
||||
regtestUtils.broadcast(txb.build().toHex(), done)
|
||||
})
|
||||
// build and broadcast to the RegTest network
|
||||
await regtestUtils.broadcast(txb.build().toHex())
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2MS(2 of 4)) (multisig) input', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2MS(2 of 4)) (multisig) input', async () => {
|
||||
const keyPairs = [
|
||||
bitcoin.ECPair.makeRandom({ network: regtest }),
|
||||
bitcoin.ECPair.makeRandom({ network: regtest }),
|
||||
|
@ -108,118 +102,102 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys: pubkeys, network: regtest })
|
||||
const p2sh = bitcoin.payments.p2sh({ redeem: p2ms, network: regtest })
|
||||
|
||||
regtestUtils.faucet(p2sh.address, 2e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(p2sh.address, 2e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
|
||||
|
||||
txb.sign(0, keyPairs[0], p2sh.redeem.output)
|
||||
txb.sign(0, keyPairs[2], p2sh.redeem.output)
|
||||
const tx = txb.build()
|
||||
txb.sign(0, keyPairs[0], p2sh.redeem.output)
|
||||
txb.sign(0, keyPairs[2], p2sh.redeem.output)
|
||||
const tx = txb.build()
|
||||
|
||||
// build and broadcast to the Bitcoin RegTest network
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
// build and broadcast to the Bitcoin RegTest network
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 1e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 1e4
|
||||
})
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input', async () => {
|
||||
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: regtest })
|
||||
const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network: regtest })
|
||||
|
||||
regtestUtils.faucet(p2sh.address, 5e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(p2sh.address, 5e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
txb.sign(0, keyPair, p2sh.redeem.output, null, unspent.value)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
txb.sign(0, keyPair, p2sh.redeem.output, null, unspent.value)
|
||||
|
||||
const tx = txb.build()
|
||||
const tx = txb.build()
|
||||
|
||||
// build and broadcast to the Bitcoin RegTest network
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
// build and broadcast to the Bitcoin RegTest network
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 2e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 2e4
|
||||
})
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', async () => {
|
||||
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: regtest })
|
||||
|
||||
regtestUtils.faucetComplex(p2wpkh.address, 5e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucetComplex(p2wpkh.address, 5e4)
|
||||
|
||||
// XXX: build the Transaction w/ a P2WPKH input
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, p2wpkh.output) // NOTE: provide the prevOutScript!
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
txb.sign(0, keyPair, null, null, unspent.value) // NOTE: no redeem script
|
||||
const tx = txb.build()
|
||||
// XXX: build the Transaction w/ a P2WPKH input
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, p2wpkh.output) // NOTE: provide the prevOutScript!
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
txb.sign(0, keyPair, null, null, unspent.value) // NOTE: no redeem script
|
||||
const tx = txb.build()
|
||||
|
||||
// build and broadcast (the P2WPKH transaction) to the Bitcoin RegTest network
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
// build and broadcast (the P2WPKH transaction) to the Bitcoin RegTest network
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 2e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 2e4
|
||||
})
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', async () => {
|
||||
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||
const p2pk = bitcoin.payments.p2pk({ pubkey: keyPair.publicKey, network: regtest })
|
||||
const p2wsh = bitcoin.payments.p2wsh({ redeem: p2pk, network: regtest })
|
||||
|
||||
regtestUtils.faucetComplex(p2wsh.address, 5e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucetComplex(p2wsh.address, 5e4)
|
||||
|
||||
// XXX: build the Transaction w/ a P2WSH input
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, p2wsh.output) // NOTE: provide the prevOutScript!
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
txb.sign(0, keyPair, null, null, 5e4, p2wsh.redeem.output) // NOTE: provide a witnessScript!
|
||||
const tx = txb.build()
|
||||
// XXX: build the Transaction w/ a P2WSH input
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, p2wsh.output) // NOTE: provide the prevOutScript!
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||
txb.sign(0, keyPair, null, null, 5e4, p2wsh.redeem.output) // NOTE: provide a witnessScript!
|
||||
const tx = txb.build()
|
||||
|
||||
// build and broadcast (the P2WSH transaction) to the Bitcoin RegTest network
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
// build and broadcast (the P2WSH transaction) to the Bitcoin RegTest network
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 2e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 2e4
|
||||
})
|
||||
})
|
||||
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input', function (done) {
|
||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input', async () => {
|
||||
const keyPairs = [
|
||||
bitcoin.ECPair.makeRandom({ network: regtest }),
|
||||
bitcoin.ECPair.makeRandom({ network: regtest }),
|
||||
|
@ -232,43 +210,39 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
const p2wsh = bitcoin.payments.p2wsh({ redeem: p2ms, network: regtest })
|
||||
const p2sh = bitcoin.payments.p2sh({ redeem: p2wsh, network: regtest })
|
||||
|
||||
regtestUtils.faucet(p2sh.address, 6e4, function (err, unspent) {
|
||||
if (err) return done(err)
|
||||
const unspent = await regtestUtils.faucet(p2sh.address, 6e4)
|
||||
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, p2sh.output)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 3e4)
|
||||
txb.sign(0, keyPairs[0], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
|
||||
txb.sign(0, keyPairs[2], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
|
||||
txb.sign(0, keyPairs[3], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
|
||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||
txb.addInput(unspent.txId, unspent.vout, null, p2sh.output)
|
||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 3e4)
|
||||
txb.sign(0, keyPairs[0], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
|
||||
txb.sign(0, keyPairs[2], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
|
||||
txb.sign(0, keyPairs[3], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output)
|
||||
|
||||
const tx = txb.build()
|
||||
const tx = txb.build()
|
||||
|
||||
// build and broadcast to the Bitcoin RegTest network
|
||||
regtestUtils.broadcast(tx.toHex(), function (err) {
|
||||
if (err) return done(err)
|
||||
// build and broadcast to the Bitcoin RegTest network
|
||||
await regtestUtils.broadcast(tx.toHex())
|
||||
|
||||
regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 3e4
|
||||
}, done)
|
||||
})
|
||||
await regtestUtils.verify({
|
||||
txId: tx.getId(),
|
||||
address: regtestUtils.RANDOM_ADDRESS,
|
||||
vout: 0,
|
||||
value: 3e4
|
||||
})
|
||||
})
|
||||
|
||||
it('can verify Transaction (P2PKH) signatures', function () {
|
||||
it('can verify Transaction (P2PKH) signatures', () => {
|
||||
const txHex = '010000000321c5f7e7bc98b3feda84aad36a5c99a02bcb8823a2f3eccbcd5da209698b5c20000000006b48304502210099e021772830207cf7c55b69948d3b16b4dcbf1f55a9cd80ebf8221a169735f9022064d33f11d62cd28240b3862afc0b901adc9f231c7124dd19bdb30367b61964c50121032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63dffffffff8a75ce85441ddb3f342708ee33cc8ed418b07d9ba9e0e7c4e1cccfe9f52d8a88000000006946304302207916c23dae212c95a920423902fa44e939fb3d542f4478a7b46e9cde53705800021f0d74e9504146e404c1b8f9cba4dff2d4782e3075491c9ed07ce4a7d1c4461a01210216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2affffffffdfef93f69fe32e944fad79fa8f882b3a155d80383252348caba1a77a5abbf7ef000000006b483045022100faa6e9ca289b46c64764a624c59ac30d9abcf1d4a04c4de9089e67cbe0d300a502206930afa683f6807502de5c2431bf9a1fd333c8a2910a76304df0f3d23d83443f0121039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18fffffffff01ff4b0000000000001976a9146c86476d1d85cd60116cd122a274e6a570a5a35c88acc96d0700'
|
||||
const keyPairs = [
|
||||
'032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63d',
|
||||
'0216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2a',
|
||||
'039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18f'
|
||||
].map(function (q) { return bitcoin.ECPair.fromPublicKey(Buffer.from(q, 'hex')) })
|
||||
].map(q => { return bitcoin.ECPair.fromPublicKey(Buffer.from(q, 'hex')) })
|
||||
|
||||
const tx = bitcoin.Transaction.fromHex(txHex)
|
||||
|
||||
tx.ins.forEach(function (input, i) {
|
||||
tx.ins.forEach((input, i) => {
|
||||
const keyPair = keyPairs[i]
|
||||
const p2pkh = bitcoin.payments.p2pkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
|
@ -282,7 +256,7 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
})
|
||||
})
|
||||
|
||||
it('can verify Transaction (P2SH(P2WPKH)) signatures', function () {
|
||||
it('can verify Transaction (P2SH(P2WPKH)) signatures', () => {
|
||||
const utxos = {
|
||||
'f72d1d83ac40fcedd01415751556a905844ab5f44bbb7728565ebb91b1590109:0': {
|
||||
value: 50000
|
||||
|
@ -292,7 +266,7 @@ describe('bitcoinjs-lib (transactions)', function () {
|
|||
const txHex = '02000000000101090159b191bb5e562877bb4bf4b54a8405a95615751514d0edfc40ac831d2df7000000001716001435a179e5516947a39ae9c8a25e9fe62c0fc598edffffffff01204e0000000000001976a91431d43308d3c886d53e9ae8a45728370571ff456988ac0247304402206ec41f685b997a51f325b07ee852e82a535f6b52ef54485cc133e05168aa052a022070bafa86108acb51c77b2b259ae8fb7fd1efa10fef804fcfe9b13c2db719acf5012103fb03e9d0a9af86cbed94225dbb8bb70f6b82109bce0a61ddcf41dab6cbb4871100000000'
|
||||
const tx = bitcoin.Transaction.fromHex(txHex)
|
||||
|
||||
tx.ins.forEach(function (input, i) {
|
||||
tx.ins.forEach((input, i) => {
|
||||
const txId = Buffer.from(input.hash).reverse().toString('hex')
|
||||
const utxo = utxos[`${txId}:${i}`]
|
||||
if (!utxo) throw new Error('Missing utxo')
|
||||
|
|
|
@ -2,8 +2,8 @@ const { describe, it } = require('mocha')
|
|||
const assert = require('assert')
|
||||
const u = require('./payments.utils')
|
||||
|
||||
;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(function (p) {
|
||||
describe(p, function () {
|
||||
;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(p => {
|
||||
describe(p, () => {
|
||||
let fn
|
||||
let payment = require('../src/payments/' + p)
|
||||
if (p === 'embed') {
|
||||
|
@ -13,15 +13,15 @@ const u = require('./payments.utils')
|
|||
}
|
||||
const fixtures = require('./fixtures/' + p)
|
||||
|
||||
fixtures.valid.forEach(function (f, i) {
|
||||
it(f.description + ' as expected', function () {
|
||||
fixtures.valid.forEach((f, i) => {
|
||||
it(f.description + ' as expected', () => {
|
||||
const args = u.preform(f.arguments)
|
||||
const actual = fn(args, f.options)
|
||||
|
||||
u.equate(actual, f.expected, f.arguments)
|
||||
})
|
||||
|
||||
it(f.description + ' as expected (no validation)', function () {
|
||||
it(f.description + ' as expected (no validation)', () => {
|
||||
const args = u.preform(f.arguments)
|
||||
const actual = fn(args, Object.assign({}, f.options, {
|
||||
validate: false
|
||||
|
@ -31,11 +31,11 @@ const u = require('./payments.utils')
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.forEach(function (f) {
|
||||
it('throws ' + f.exception + (f.description ? ('for ' + f.description) : ''), function () {
|
||||
fixtures.invalid.forEach(f => {
|
||||
it('throws ' + f.exception + (f.description ? ('for ' + f.description) : ''), () => {
|
||||
const args = u.preform(f.arguments)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
fn(args, f.options)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
|
@ -45,23 +45,23 @@ const u = require('./payments.utils')
|
|||
if (!fixtures.dynamic) return
|
||||
const { depends, details } = fixtures.dynamic
|
||||
|
||||
details.forEach(function (f) {
|
||||
details.forEach(f => {
|
||||
const detail = u.preform(f)
|
||||
const disabled = {}
|
||||
if (f.disabled) f.disabled.forEach(function (k) { disabled[k] = true })
|
||||
if (f.disabled) f.disabled.forEach(k => { disabled[k] = true })
|
||||
|
||||
for (let key in depends) {
|
||||
if (key in disabled) continue
|
||||
const dependencies = depends[key]
|
||||
|
||||
dependencies.forEach(function (dependency) {
|
||||
dependencies.forEach(dependency => {
|
||||
if (!Array.isArray(dependency)) dependency = [dependency]
|
||||
|
||||
const args = {}
|
||||
dependency.forEach(function (d) { u.from(d, detail, args) })
|
||||
dependency.forEach(d => { u.from(d, detail, args) })
|
||||
const expected = u.from(key, detail)
|
||||
|
||||
it(f.description + ', ' + key + ' derives from ' + JSON.stringify(dependency), function () {
|
||||
it(f.description + ', ' + key + ' derives from ' + JSON.stringify(dependency), () => {
|
||||
u.equate(fn(args), expected)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -39,7 +39,7 @@ function carryOver (a, b) {
|
|||
function equateBase (a, b, context) {
|
||||
if ('output' in b) t.strictEqual(tryASM(a.output), tryASM(b.output), `Inequal ${context}output`)
|
||||
if ('input' in b) t.strictEqual(tryASM(a.input), tryASM(b.input), `Inequal ${context}input`)
|
||||
if ('witness' in b) t.deepEqual(tryHex(a.witness), tryHex(b.witness), `Inequal ${context}witness`)
|
||||
if ('witness' in b) t.deepStrictEqual(tryHex(a.witness), tryHex(b.witness), `Inequal ${context}witness`)
|
||||
}
|
||||
|
||||
function equate (a, b, args) {
|
||||
|
@ -58,19 +58,20 @@ function equate (a, b, args) {
|
|||
|
||||
equateBase(a, b, '')
|
||||
if (b.redeem) equateBase(a.redeem, b.redeem, 'redeem.')
|
||||
if (b.network) t.deepEqual(a.network, BNETWORKS[b.network], 'Inequal *.network')
|
||||
if (b.network) t.deepStrictEqual(a.network, BNETWORKS[b.network], 'Inequal *.network')
|
||||
|
||||
// contextual
|
||||
if (b.signature === null) b.signature = undefined
|
||||
if (b.signatures === null) b.signatures = undefined
|
||||
if ('address' in b) t.strictEqual(a.address, b.address, 'Inequal *.address')
|
||||
if ('hash' in b) t.strictEqual(tryHex(a.hash), tryHex(b.hash), 'Inequal *.hash')
|
||||
if ('pubkey' in b) t.strictEqual(tryHex(a.pubkey), tryHex(b.pubkey), 'Inequal *.pubkey')
|
||||
if ('signature' in b) t.strictEqual(tryHex(a.signature), tryHex(b.signature), 'Inequal signature')
|
||||
if ('m' in b) t.strictEqual(a.m, b.m, 'Inequal *.m')
|
||||
if ('n' in b) t.strictEqual(a.n, b.n, 'Inequal *.n')
|
||||
if ('pubkeys' in b) t.deepEqual(tryHex(a.pubkeys), tryHex(b.pubkeys), 'Inequal *.pubkeys')
|
||||
if ('signatures' in b) t.deepEqual(tryHex(a.signatures), tryHex(b.signatures), 'Inequal *.signatures')
|
||||
if ('data' in b) t.deepEqual(tryHex(a.data), tryHex(b.data), 'Inequal *.data')
|
||||
if ('pubkeys' in b) t.deepStrictEqual(tryHex(a.pubkeys), tryHex(b.pubkeys), 'Inequal *.pubkeys')
|
||||
if ('signatures' in b) t.deepStrictEqual(tryHex(a.signatures), tryHex(b.signatures), 'Inequal *.signatures')
|
||||
if ('data' in b) t.deepStrictEqual(tryHex(a.data), tryHex(b.data), 'Inequal *.data')
|
||||
}
|
||||
|
||||
function preform (x) {
|
||||
|
@ -94,7 +95,7 @@ function preform (x) {
|
|||
if (x.pubkey) x.pubkey = Buffer.from(x.pubkey, 'hex')
|
||||
if (x.signature) x.signature = Buffer.from(x.signature, 'hex')
|
||||
if (x.pubkeys) x.pubkeys = x.pubkeys.map(fromHex)
|
||||
if (x.signatures) x.signatures = x.signatures.map(function (y) { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') })
|
||||
if (x.signatures) x.signatures = x.signatures.map(y => { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') })
|
||||
if (x.redeem) {
|
||||
x.redeem = Object.assign({}, x.redeem)
|
||||
if (typeof x.redeem.input === 'string') x.redeem.input = asmToBuffer(x.redeem.input)
|
||||
|
|
|
@ -6,44 +6,44 @@ const minimalData = require('minimaldata')
|
|||
const fixtures = require('./fixtures/script.json')
|
||||
const fixtures2 = require('./fixtures/templates.json')
|
||||
|
||||
describe('script', function () {
|
||||
describe('script', () => {
|
||||
// TODO
|
||||
describe('isCanonicalPubKey', function () {
|
||||
it('rejects if not provided a Buffer', function () {
|
||||
describe('isCanonicalPubKey', () => {
|
||||
it('rejects if not provided a Buffer', () => {
|
||||
assert.strictEqual(false, bscript.isCanonicalPubKey(0))
|
||||
})
|
||||
it('rejects smaller than 33', function () {
|
||||
it('rejects smaller than 33', () => {
|
||||
for (var i = 0; i < 33; i++) {
|
||||
assert.strictEqual(false, bscript.isCanonicalPubKey(Buffer.from('', i)))
|
||||
}
|
||||
})
|
||||
})
|
||||
describe.skip('isCanonicalScriptSignature', function () {
|
||||
describe.skip('isCanonicalScriptSignature', () => {
|
||||
})
|
||||
|
||||
describe('fromASM/toASM', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('encodes/decodes ' + f.asm, function () {
|
||||
describe('fromASM/toASM', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('encodes/decodes ' + f.asm, () => {
|
||||
const script = bscript.fromASM(f.asm)
|
||||
assert.strictEqual(bscript.toASM(script), f.asm)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.fromASM.forEach(function (f) {
|
||||
it('throws ' + f.description, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.fromASM.forEach(f => {
|
||||
it('throws ' + f.description, () => {
|
||||
assert.throws(() => {
|
||||
bscript.fromASM(f.script)
|
||||
}, new RegExp(f.description))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fromASM/toASM (templates)', function () {
|
||||
fixtures2.valid.forEach(function (f) {
|
||||
describe('fromASM/toASM (templates)', () => {
|
||||
fixtures2.valid.forEach(f => {
|
||||
if (f.inputHex) {
|
||||
const ih = bscript.toASM(Buffer.from(f.inputHex, 'hex'))
|
||||
|
||||
it('encodes/decodes ' + ih, function () {
|
||||
it('encodes/decodes ' + ih, () => {
|
||||
const script = bscript.fromASM(f.input)
|
||||
assert.strictEqual(script.toString('hex'), f.inputHex)
|
||||
assert.strictEqual(bscript.toASM(script), f.input)
|
||||
|
@ -51,7 +51,7 @@ describe('script', function () {
|
|||
}
|
||||
|
||||
if (f.outputHex) {
|
||||
it('encodes/decodes ' + f.output, function () {
|
||||
it('encodes/decodes ' + f.output, () => {
|
||||
const script = bscript.fromASM(f.output)
|
||||
assert.strictEqual(script.toString('hex'), f.outputHex)
|
||||
assert.strictEqual(bscript.toASM(script), f.output)
|
||||
|
@ -60,9 +60,9 @@ describe('script', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('isPushOnly', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('returns ' + !!f.stack + ' for ' + f.asm, function () {
|
||||
describe('isPushOnly', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('returns ' + !!f.stack + ' for ' + f.asm, () => {
|
||||
const script = bscript.fromASM(f.asm)
|
||||
const chunks = bscript.decompile(script)
|
||||
|
||||
|
@ -71,26 +71,26 @@ describe('script', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('toStack', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('returns ' + !!f.stack + ' for ' + f.asm, function () {
|
||||
describe('toStack', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('returns ' + !!f.stack + ' for ' + f.asm, () => {
|
||||
if (!f.stack || !f.asm) return
|
||||
|
||||
const script = bscript.fromASM(f.asm)
|
||||
|
||||
const stack = bscript.toStack(script)
|
||||
assert.deepEqual(stack.map(function (x) {
|
||||
assert.deepStrictEqual(stack.map(x => {
|
||||
return x.toString('hex')
|
||||
}), f.stack)
|
||||
|
||||
assert.equal(bscript.toASM(bscript.compile(stack)), f.asm, 'should rebuild same script from stack')
|
||||
assert.strictEqual(bscript.toASM(bscript.compile(stack)), f.asm, 'should rebuild same script from stack')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('compile (via fromASM)', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('(' + f.type + ') compiles ' + f.asm, function () {
|
||||
describe('compile (via fromASM)', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('(' + f.type + ') compiles ' + f.asm, () => {
|
||||
const scriptSig = bscript.fromASM(f.asm)
|
||||
|
||||
assert.strictEqual(scriptSig.toString('hex'), f.script)
|
||||
|
@ -104,9 +104,9 @@ describe('script', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('decompile', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('decompiles ' + f.asm, function () {
|
||||
describe('decompile', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('decompiles ' + f.asm, () => {
|
||||
const chunks = bscript.decompile(Buffer.from(f.script, 'hex'))
|
||||
|
||||
assert.strictEqual(bscript.compile(chunks).toString('hex'), f.script)
|
||||
|
@ -123,8 +123,8 @@ describe('script', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.decompile.forEach(function (f) {
|
||||
it('fails to decompile ' + f.script + ', because "' + f.description + '"', function () {
|
||||
fixtures.invalid.decompile.forEach(f => {
|
||||
it('fails to decompile ' + f.script + ', because "' + f.description + '"', () => {
|
||||
const chunks = bscript.decompile(Buffer.from(f.script, 'hex'))
|
||||
|
||||
assert.strictEqual(chunks, null)
|
||||
|
@ -132,9 +132,9 @@ describe('script', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('SCRIPT_VERIFY_MINIMALDATA policy', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('compliant for ' + f.type + ' scriptSig ' + f.asm, function () {
|
||||
describe('SCRIPT_VERIFY_MINIMALDATA policy', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('compliant for ' + f.type + ' scriptSig ' + f.asm, () => {
|
||||
const script = Buffer.from(f.script, 'hex')
|
||||
|
||||
assert(minimalData(script))
|
||||
|
@ -142,7 +142,7 @@ describe('script', function () {
|
|||
})
|
||||
|
||||
function testEncodingForSize (i) {
|
||||
it('compliant for data PUSH of length ' + i, function () {
|
||||
it('compliant for data PUSH of length ' + i, () => {
|
||||
const buffer = Buffer.alloc(i)
|
||||
const script = bscript.compile([buffer])
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ const assert = require('assert')
|
|||
const scriptNumber = require('../src/script_number')
|
||||
const fixtures = require('./fixtures/script_number.json')
|
||||
|
||||
describe('script-number', function () {
|
||||
describe('decode', function () {
|
||||
fixtures.forEach(function (f) {
|
||||
it(f.hex + ' returns ' + f.number, function () {
|
||||
describe('script-number', () => {
|
||||
describe('decode', () => {
|
||||
fixtures.forEach(f => {
|
||||
it(f.hex + ' returns ' + f.number, () => {
|
||||
const actual = scriptNumber.decode(Buffer.from(f.hex, 'hex'), f.bytes)
|
||||
|
||||
assert.strictEqual(actual, f.number)
|
||||
|
@ -14,9 +14,9 @@ describe('script-number', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('encode', function () {
|
||||
fixtures.forEach(function (f) {
|
||||
it(f.number + ' returns ' + f.hex, function () {
|
||||
describe('encode', () => {
|
||||
fixtures.forEach(f => {
|
||||
it(f.number + ' returns ' + f.hex, () => {
|
||||
const actual = scriptNumber.encode(f.number)
|
||||
|
||||
assert.strictEqual(actual.toString('hex'), f.hex)
|
||||
|
|
|
@ -4,7 +4,7 @@ const bscriptSig = require('../src/script').signature
|
|||
const Buffer = require('safe-buffer').Buffer
|
||||
const fixtures = require('./fixtures/signature.json')
|
||||
|
||||
describe('Script Signatures', function () {
|
||||
describe('Script Signatures', () => {
|
||||
function fromRaw (signature) {
|
||||
return Buffer.concat([
|
||||
Buffer.from(signature.r, 'hex'),
|
||||
|
@ -19,43 +19,43 @@ describe('Script Signatures', function () {
|
|||
}
|
||||
}
|
||||
|
||||
describe('encode', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('encodes ' + f.hex, function () {
|
||||
describe('encode', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('encodes ' + f.hex, () => {
|
||||
const buffer = bscriptSig.encode(fromRaw(f.raw), f.hashType)
|
||||
|
||||
assert.strictEqual(buffer.toString('hex'), f.hex)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.forEach(function (f) {
|
||||
fixtures.invalid.forEach(f => {
|
||||
if (!f.raw) return
|
||||
|
||||
it('throws ' + f.exception, function () {
|
||||
it('throws ' + f.exception, () => {
|
||||
const signature = fromRaw(f.raw)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
bscriptSig.encode(signature, f.hashType)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('decode', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('decodes ' + f.hex, function () {
|
||||
describe('decode', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('decodes ' + f.hex, () => {
|
||||
const decode = bscriptSig.decode(Buffer.from(f.hex, 'hex'))
|
||||
|
||||
assert.deepEqual(toRaw(decode.signature), f.raw)
|
||||
assert.deepStrictEqual(toRaw(decode.signature), f.raw)
|
||||
assert.strictEqual(decode.hashType, f.hashType)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.forEach(function (f) {
|
||||
it('throws on ' + f.hex, function () {
|
||||
fixtures.invalid.forEach(f => {
|
||||
it('throws on ' + f.hex, () => {
|
||||
const buffer = Buffer.from(f.hex, 'hex')
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
bscriptSig.decode(buffer)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
|
|
|
@ -4,13 +4,13 @@ const bscript = require('../src/script')
|
|||
const fixtures = require('./fixtures/transaction')
|
||||
const Transaction = require('..').Transaction
|
||||
|
||||
describe('Transaction', function () {
|
||||
describe('Transaction', () => {
|
||||
function fromRaw (raw, noWitness) {
|
||||
const tx = new Transaction()
|
||||
tx.version = raw.version
|
||||
tx.locktime = raw.locktime
|
||||
|
||||
raw.ins.forEach(function (txIn, i) {
|
||||
raw.ins.forEach((txIn, i) => {
|
||||
const txHash = Buffer.from(txIn.hash, 'hex')
|
||||
let scriptSig
|
||||
|
||||
|
@ -23,7 +23,7 @@ describe('Transaction', function () {
|
|||
tx.addInput(txHash, txIn.index, txIn.sequence, scriptSig)
|
||||
|
||||
if (!noWitness && txIn.witness) {
|
||||
const witness = txIn.witness.map(function (x) {
|
||||
const witness = txIn.witness.map(x => {
|
||||
return Buffer.from(x, 'hex')
|
||||
})
|
||||
|
||||
|
@ -31,7 +31,7 @@ describe('Transaction', function () {
|
|||
}
|
||||
})
|
||||
|
||||
raw.outs.forEach(function (txOut) {
|
||||
raw.outs.forEach(txOut => {
|
||||
let script
|
||||
|
||||
if (txOut.data) {
|
||||
|
@ -46,19 +46,19 @@ describe('Transaction', function () {
|
|||
return tx
|
||||
}
|
||||
|
||||
describe('fromBuffer/fromHex', function () {
|
||||
describe('fromBuffer/fromHex', () => {
|
||||
function importExport (f) {
|
||||
const id = f.id || f.hash
|
||||
const txHex = f.hex || f.txHex
|
||||
|
||||
it('imports ' + f.description + ' (' + id + ')', function () {
|
||||
it('imports ' + f.description + ' (' + id + ')', () => {
|
||||
const actual = Transaction.fromHex(txHex)
|
||||
|
||||
assert.strictEqual(actual.toHex(), txHex)
|
||||
})
|
||||
|
||||
if (f.whex) {
|
||||
it('imports ' + f.description + ' (' + id + ') as witness', function () {
|
||||
it('imports ' + f.description + ' (' + id + ') as witness', () => {
|
||||
const actual = Transaction.fromHex(f.whex)
|
||||
|
||||
assert.strictEqual(actual.toHex(), f.whex)
|
||||
|
@ -70,38 +70,38 @@ describe('Transaction', function () {
|
|||
fixtures.hashForSignature.forEach(importExport)
|
||||
fixtures.hashForWitnessV0.forEach(importExport)
|
||||
|
||||
fixtures.invalid.fromBuffer.forEach(function (f) {
|
||||
it('throws on ' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.fromBuffer.forEach(f => {
|
||||
it('throws on ' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
Transaction.fromHex(f.hex)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
|
||||
it('.version should be interpreted as an int32le', function () {
|
||||
it('.version should be interpreted as an int32le', () => {
|
||||
const txHex = 'ffffffff0000ffffffff'
|
||||
const tx = Transaction.fromHex(txHex)
|
||||
assert.equal(-1, tx.version)
|
||||
assert.equal(0xffffffff, tx.locktime)
|
||||
assert.strictEqual(-1, tx.version)
|
||||
assert.strictEqual(0xffffffff, tx.locktime)
|
||||
})
|
||||
})
|
||||
|
||||
describe('toBuffer/toHex', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('exports ' + f.description + ' (' + f.id + ')', function () {
|
||||
describe('toBuffer/toHex', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('exports ' + f.description + ' (' + f.id + ')', () => {
|
||||
const actual = fromRaw(f.raw, true)
|
||||
assert.strictEqual(actual.toHex(), f.hex)
|
||||
})
|
||||
|
||||
if (f.whex) {
|
||||
it('exports ' + f.description + ' (' + f.id + ') as witness', function () {
|
||||
it('exports ' + f.description + ' (' + f.id + ') as witness', () => {
|
||||
const wactual = fromRaw(f.raw)
|
||||
assert.strictEqual(wactual.toHex(), f.whex)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('accepts target Buffer and offset parameters', function () {
|
||||
it('accepts target Buffer and offset parameters', () => {
|
||||
const f = fixtures.valid[0]
|
||||
const actual = fromRaw(f.raw)
|
||||
const byteLength = actual.byteLength()
|
||||
|
@ -114,31 +114,31 @@ describe('Transaction', function () {
|
|||
assert.strictEqual(b.length, byteLength)
|
||||
assert.strictEqual(a.toString('hex'), f.hex)
|
||||
assert.strictEqual(b.toString('hex'), f.hex)
|
||||
assert.deepEqual(a, b)
|
||||
assert.deepEqual(a, target.slice(0, byteLength))
|
||||
assert.deepEqual(b, target.slice(byteLength))
|
||||
assert.deepStrictEqual(a, b)
|
||||
assert.deepStrictEqual(a, target.slice(0, byteLength))
|
||||
assert.deepStrictEqual(b, target.slice(byteLength))
|
||||
})
|
||||
})
|
||||
|
||||
describe('hasWitnesses', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('detects if the transaction has witnesses: ' + (f.whex ? 'true' : 'false'), function () {
|
||||
describe('hasWitnesses', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
it('detects if the transaction has witnesses: ' + (f.whex ? 'true' : 'false'), () => {
|
||||
assert.strictEqual(Transaction.fromHex(f.whex ? f.whex : f.hex).hasWitnesses(), !!f.whex)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('weight/virtualSize', function () {
|
||||
it('computes virtual size', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('weight/virtualSize', () => {
|
||||
it('computes virtual size', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
const transaction = Transaction.fromHex(f.whex ? f.whex : f.hex)
|
||||
|
||||
assert.strictEqual(transaction.virtualSize(), f.virtualSize)
|
||||
})
|
||||
})
|
||||
|
||||
it('computes weight', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
it('computes weight', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
const transaction = Transaction.fromHex(f.whex ? f.whex : f.hex)
|
||||
|
||||
assert.strictEqual(transaction.weight(), f.weight)
|
||||
|
@ -146,19 +146,19 @@ describe('Transaction', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('addInput', function () {
|
||||
describe('addInput', () => {
|
||||
let prevTxHash
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
prevTxHash = Buffer.from('ffffffff00ffff000000000000000000000000000000000000000000101010ff', 'hex')
|
||||
})
|
||||
|
||||
it('returns an index', function () {
|
||||
it('returns an index', () => {
|
||||
const tx = new Transaction()
|
||||
assert.strictEqual(tx.addInput(prevTxHash, 0), 0)
|
||||
assert.strictEqual(tx.addInput(prevTxHash, 0), 1)
|
||||
})
|
||||
|
||||
it('defaults to empty script, witness and 0xffffffff SEQUENCE number', function () {
|
||||
it('defaults to empty script, witness and 0xffffffff SEQUENCE number', () => {
|
||||
const tx = new Transaction()
|
||||
tx.addInput(prevTxHash, 0)
|
||||
|
||||
|
@ -167,49 +167,49 @@ describe('Transaction', function () {
|
|||
assert.strictEqual(tx.ins[0].sequence, 0xffffffff)
|
||||
})
|
||||
|
||||
fixtures.invalid.addInput.forEach(function (f) {
|
||||
it('throws on ' + f.exception, function () {
|
||||
fixtures.invalid.addInput.forEach(f => {
|
||||
it('throws on ' + f.exception, () => {
|
||||
const tx = new Transaction()
|
||||
const hash = Buffer.from(f.hash, 'hex')
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
tx.addInput(hash, f.index)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('addOutput', function () {
|
||||
it('returns an index', function () {
|
||||
describe('addOutput', () => {
|
||||
it('returns an index', () => {
|
||||
const tx = new Transaction()
|
||||
assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 0)
|
||||
assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('clone', function () {
|
||||
fixtures.valid.forEach(function (f) {
|
||||
describe('clone', () => {
|
||||
fixtures.valid.forEach(f => {
|
||||
let actual
|
||||
let expected
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
expected = Transaction.fromHex(f.hex)
|
||||
actual = expected.clone()
|
||||
})
|
||||
|
||||
it('should have value equality', function () {
|
||||
assert.deepEqual(actual, expected)
|
||||
it('should have value equality', () => {
|
||||
assert.deepStrictEqual(actual, expected)
|
||||
})
|
||||
|
||||
it('should not have reference equality', function () {
|
||||
assert.notEqual(actual, expected)
|
||||
it('should not have reference equality', () => {
|
||||
assert.notStrictEqual(actual, expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getHash/getId', function () {
|
||||
describe('getHash/getId', () => {
|
||||
function verify (f) {
|
||||
it('should return the id for ' + f.id + '(' + f.description + ')', function () {
|
||||
it('should return the id for ' + f.id + '(' + f.description + ')', () => {
|
||||
const tx = Transaction.fromHex(f.whex || f.hex)
|
||||
|
||||
assert.strictEqual(tx.getHash().toString('hex'), f.hash)
|
||||
|
@ -220,9 +220,9 @@ describe('Transaction', function () {
|
|||
fixtures.valid.forEach(verify)
|
||||
})
|
||||
|
||||
describe('isCoinbase', function () {
|
||||
describe('isCoinbase', () => {
|
||||
function verify (f) {
|
||||
it('should return ' + f.coinbase + ' for ' + f.id + '(' + f.description + ')', function () {
|
||||
it('should return ' + f.coinbase + ' for ' + f.id + '(' + f.description + ')', () => {
|
||||
const tx = Transaction.fromHex(f.hex)
|
||||
|
||||
assert.strictEqual(tx.isCoinbase(), f.coinbase)
|
||||
|
@ -232,8 +232,8 @@ describe('Transaction', function () {
|
|||
fixtures.valid.forEach(verify)
|
||||
})
|
||||
|
||||
describe('hashForSignature', function () {
|
||||
it('does not use Witness serialization', function () {
|
||||
describe('hashForSignature', () => {
|
||||
it('does not use Witness serialization', () => {
|
||||
const randScript = Buffer.from('6a', 'hex')
|
||||
|
||||
const tx = new Transaction()
|
||||
|
@ -241,24 +241,24 @@ describe('Transaction', function () {
|
|||
tx.addOutput(randScript, 5000000000)
|
||||
|
||||
const original = tx.__toBuffer
|
||||
tx.__toBuffer = function (a, b, c) {
|
||||
tx.__toBuffer = (a, b, c) => {
|
||||
if (c !== false) throw new Error('hashForSignature MUST pass false')
|
||||
|
||||
return original.call(this, a, b, c)
|
||||
}
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
tx.__toBuffer(undefined, undefined, true)
|
||||
}, /hashForSignature MUST pass false/)
|
||||
|
||||
// assert hashForSignature does not pass false
|
||||
assert.doesNotThrow(function () {
|
||||
assert.doesNotThrow(() => {
|
||||
tx.hashForSignature(0, randScript, 1)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.hashForSignature.forEach(function (f) {
|
||||
it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : f.script), function () {
|
||||
fixtures.hashForSignature.forEach(f => {
|
||||
it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : f.script), () => {
|
||||
const tx = Transaction.fromHex(f.txHex)
|
||||
const script = bscript.fromASM(f.script)
|
||||
|
||||
|
@ -267,9 +267,9 @@ describe('Transaction', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('hashForWitnessV0', function () {
|
||||
fixtures.hashForWitnessV0.forEach(function (f) {
|
||||
it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : ''), function () {
|
||||
describe('hashForWitnessV0', () => {
|
||||
fixtures.hashForWitnessV0.forEach(f => {
|
||||
it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : ''), () => {
|
||||
const tx = Transaction.fromHex(f.txHex)
|
||||
const script = bscript.fromASM(f.script)
|
||||
|
||||
|
@ -278,9 +278,9 @@ describe('Transaction', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('setWitness', function () {
|
||||
it('only accepts a a witness stack (Array of Buffers)', function () {
|
||||
assert.throws(function () {
|
||||
describe('setWitness', () => {
|
||||
it('only accepts a a witness stack (Array of Buffers)', () => {
|
||||
assert.throws(() => {
|
||||
(new Transaction()).setWitness(0, 'foobar')
|
||||
}, /Expected property "1" of type \[Buffer], got String "foobar"/)
|
||||
})
|
||||
|
|
|
@ -15,9 +15,9 @@ function constructSign (f, txb) {
|
|||
const network = NETWORKS[f.network]
|
||||
const stages = f.stages && f.stages.concat()
|
||||
|
||||
f.inputs.forEach(function (input, index) {
|
||||
f.inputs.forEach((input, index) => {
|
||||
if (!input.signs) return
|
||||
input.signs.forEach(function (sign) {
|
||||
input.signs.forEach(sign => {
|
||||
const keyPair = ECPair.fromWIF(sign.keyPair, network)
|
||||
let redeemScript
|
||||
let witnessScript
|
||||
|
@ -55,7 +55,7 @@ function construct (f, dontSign) {
|
|||
if (Number.isFinite(f.version)) txb.setVersion(f.version)
|
||||
if (f.locktime !== undefined) txb.setLockTime(f.locktime)
|
||||
|
||||
f.inputs.forEach(function (input) {
|
||||
f.inputs.forEach(input => {
|
||||
let prevTx
|
||||
if (input.txRaw) {
|
||||
const constructed = construct(input.txRaw)
|
||||
|
@ -75,7 +75,7 @@ function construct (f, dontSign) {
|
|||
txb.addInput(prevTx, input.vout, input.sequence, prevTxScript)
|
||||
})
|
||||
|
||||
f.outputs.forEach(function (output) {
|
||||
f.outputs.forEach(output => {
|
||||
if (output.address) {
|
||||
txb.addOutput(output.address, output.value)
|
||||
} else {
|
||||
|
@ -87,20 +87,20 @@ function construct (f, dontSign) {
|
|||
return constructSign(f, txb)
|
||||
}
|
||||
|
||||
describe('TransactionBuilder', function () {
|
||||
describe('TransactionBuilder', () => {
|
||||
// constants
|
||||
const keyPair = ECPair.fromPrivateKey(Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'))
|
||||
const scripts = [
|
||||
'1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH',
|
||||
'1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP'
|
||||
].map(function (x) {
|
||||
].map(x => {
|
||||
return baddress.toOutputScript(x)
|
||||
})
|
||||
const txHash = Buffer.from('0e7cea811c0be9f73c0aca591034396e7264473fc25c1ca45195d7417b36cbe2', 'hex')
|
||||
|
||||
describe('fromTransaction', function () {
|
||||
fixtures.valid.build.forEach(function (f) {
|
||||
it('returns TransactionBuilder, with ' + f.description, function () {
|
||||
describe('fromTransaction', () => {
|
||||
fixtures.valid.build.forEach(f => {
|
||||
it('returns TransactionBuilder, with ' + f.description, () => {
|
||||
const network = NETWORKS[f.network || 'bitcoin']
|
||||
|
||||
const tx = Transaction.fromHex(f.txHex)
|
||||
|
@ -112,82 +112,82 @@ describe('TransactionBuilder', function () {
|
|||
})
|
||||
})
|
||||
|
||||
fixtures.valid.fromTransaction.forEach(function (f) {
|
||||
it('returns TransactionBuilder, with ' + f.description, function () {
|
||||
fixtures.valid.fromTransaction.forEach(f => {
|
||||
it('returns TransactionBuilder, with ' + f.description, () => {
|
||||
const tx = new Transaction()
|
||||
|
||||
f.inputs.forEach(function (input) {
|
||||
f.inputs.forEach(input => {
|
||||
const txHash2 = Buffer.from(input.txId, 'hex').reverse()
|
||||
|
||||
tx.addInput(txHash2, input.vout, undefined, bscript.fromASM(input.scriptSig))
|
||||
})
|
||||
|
||||
f.outputs.forEach(function (output) {
|
||||
f.outputs.forEach(output => {
|
||||
tx.addOutput(bscript.fromASM(output.script), output.value)
|
||||
})
|
||||
|
||||
const txb = TransactionBuilder.fromTransaction(tx)
|
||||
const txAfter = f.incomplete ? txb.buildIncomplete() : txb.build()
|
||||
|
||||
txAfter.ins.forEach(function (input, i) {
|
||||
assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSigAfter)
|
||||
txAfter.ins.forEach((input, i) => {
|
||||
assert.strictEqual(bscript.toASM(input.script), f.inputs[i].scriptSigAfter)
|
||||
})
|
||||
|
||||
txAfter.outs.forEach(function (output, i) {
|
||||
assert.equal(bscript.toASM(output.script), f.outputs[i].script)
|
||||
txAfter.outs.forEach((output, i) => {
|
||||
assert.strictEqual(bscript.toASM(output.script), f.outputs[i].script)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.valid.fromTransactionSequential.forEach(function (f) {
|
||||
it('with ' + f.description, function () {
|
||||
fixtures.valid.fromTransactionSequential.forEach(f => {
|
||||
it('with ' + f.description, () => {
|
||||
const network = NETWORKS[f.network]
|
||||
const tx = Transaction.fromHex(f.txHex)
|
||||
const txb = TransactionBuilder.fromTransaction(tx, network)
|
||||
|
||||
tx.ins.forEach(function (input, i) {
|
||||
assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSig)
|
||||
tx.ins.forEach((input, i) => {
|
||||
assert.strictEqual(bscript.toASM(input.script), f.inputs[i].scriptSig)
|
||||
})
|
||||
|
||||
constructSign(f, txb)
|
||||
const txAfter = f.incomplete ? txb.buildIncomplete() : txb.build()
|
||||
|
||||
txAfter.ins.forEach(function (input, i) {
|
||||
assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSigAfter)
|
||||
txAfter.ins.forEach((input, i) => {
|
||||
assert.strictEqual(bscript.toASM(input.script), f.inputs[i].scriptSigAfter)
|
||||
})
|
||||
|
||||
assert.equal(txAfter.toHex(), f.txHexAfter)
|
||||
assert.strictEqual(txAfter.toHex(), f.txHexAfter)
|
||||
})
|
||||
})
|
||||
|
||||
it('classifies transaction inputs', function () {
|
||||
it('classifies transaction inputs', () => {
|
||||
const tx = Transaction.fromHex(fixtures.valid.classification.hex)
|
||||
const txb = TransactionBuilder.fromTransaction(tx)
|
||||
|
||||
txb.__INPUTS.forEach(function (i) {
|
||||
txb.__INPUTS.forEach(i => {
|
||||
assert.strictEqual(i.prevOutType, 'scripthash')
|
||||
assert.strictEqual(i.redeemScriptType, 'multisig')
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.fromTransaction.forEach(function (f) {
|
||||
it('throws ' + f.exception, function () {
|
||||
fixtures.invalid.fromTransaction.forEach(f => {
|
||||
it('throws ' + f.exception, () => {
|
||||
const tx = Transaction.fromHex(f.txHex)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
TransactionBuilder.fromTransaction(tx)
|
||||
}, new RegExp(f.exception))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('addInput', function () {
|
||||
describe('addInput', () => {
|
||||
let txb
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
txb = new TransactionBuilder()
|
||||
})
|
||||
|
||||
it('accepts a txHash, index [and sequence number]', function () {
|
||||
it('accepts a txHash, index [and sequence number]', () => {
|
||||
const vin = txb.addInput(txHash, 1, 54)
|
||||
assert.strictEqual(vin, 0)
|
||||
|
||||
|
@ -198,7 +198,7 @@ describe('TransactionBuilder', function () {
|
|||
assert.strictEqual(txb.__INPUTS[0].prevOutScript, undefined)
|
||||
})
|
||||
|
||||
it('accepts a txHash, index [, sequence number and scriptPubKey]', function () {
|
||||
it('accepts a txHash, index [, sequence number and scriptPubKey]', () => {
|
||||
const vin = txb.addInput(txHash, 1, 54, scripts[1])
|
||||
assert.strictEqual(vin, 0)
|
||||
|
||||
|
@ -209,7 +209,7 @@ describe('TransactionBuilder', function () {
|
|||
assert.strictEqual(txb.__INPUTS[0].prevOutScript, scripts[1])
|
||||
})
|
||||
|
||||
it('accepts a prevTx, index [and sequence number]', function () {
|
||||
it('accepts a prevTx, index [and sequence number]', () => {
|
||||
const prevTx = new Transaction()
|
||||
prevTx.addOutput(scripts[0], 0)
|
||||
prevTx.addOutput(scripts[1], 1)
|
||||
|
@ -218,116 +218,116 @@ describe('TransactionBuilder', function () {
|
|||
assert.strictEqual(vin, 0)
|
||||
|
||||
const txIn = txb.__TX.ins[0]
|
||||
assert.deepEqual(txIn.hash, prevTx.getHash())
|
||||
assert.deepStrictEqual(txIn.hash, prevTx.getHash())
|
||||
assert.strictEqual(txIn.index, 1)
|
||||
assert.strictEqual(txIn.sequence, 54)
|
||||
assert.strictEqual(txb.__INPUTS[0].prevOutScript, scripts[1])
|
||||
})
|
||||
|
||||
it('returns the input index', function () {
|
||||
it('returns the input index', () => {
|
||||
assert.strictEqual(txb.addInput(txHash, 0), 0)
|
||||
assert.strictEqual(txb.addInput(txHash, 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', () => {
|
||||
txb.addInput(txHash, 0)
|
||||
txb.addOutput(scripts[0], 1000)
|
||||
txb.sign(0, keyPair)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
txb.addInput(txHash, 0)
|
||||
}, /No, this would invalidate signatures/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addOutput', function () {
|
||||
describe('addOutput', () => {
|
||||
let txb
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
txb = new TransactionBuilder()
|
||||
})
|
||||
|
||||
it('accepts an address string and value', function () {
|
||||
it('accepts an address string and value', () => {
|
||||
const { address } = payments.p2pkh({ pubkey: keyPair.publicKey })
|
||||
const vout = txb.addOutput(address, 1000)
|
||||
assert.strictEqual(vout, 0)
|
||||
|
||||
const txout = txb.__TX.outs[0]
|
||||
assert.deepEqual(txout.script, scripts[0])
|
||||
assert.deepStrictEqual(txout.script, scripts[0])
|
||||
assert.strictEqual(txout.value, 1000)
|
||||
})
|
||||
|
||||
it('accepts a ScriptPubKey and value', function () {
|
||||
it('accepts a ScriptPubKey and value', () => {
|
||||
const vout = txb.addOutput(scripts[0], 1000)
|
||||
assert.strictEqual(vout, 0)
|
||||
|
||||
const txout = txb.__TX.outs[0]
|
||||
assert.deepEqual(txout.script, scripts[0])
|
||||
assert.deepStrictEqual(txout.script, scripts[0])
|
||||
assert.strictEqual(txout.value, 1000)
|
||||
})
|
||||
|
||||
it('throws if address is of the wrong network', function () {
|
||||
assert.throws(function () {
|
||||
it('throws if address is of the wrong network', () => {
|
||||
assert.throws(() => {
|
||||
txb.addOutput('2NGHjvjw83pcVFgMcA7QvSMh2c246rxLVz9', 1000)
|
||||
}, /2NGHjvjw83pcVFgMcA7QvSMh2c246rxLVz9 has no matching Script/)
|
||||
})
|
||||
|
||||
it('add second output after signed first input with SIGHASH_NONE', function () {
|
||||
it('add second output after signed first input with SIGHASH_NONE', () => {
|
||||
txb.addInput(txHash, 0)
|
||||
txb.addOutput(scripts[0], 2000)
|
||||
txb.sign(0, keyPair, undefined, Transaction.SIGHASH_NONE)
|
||||
assert.equal(txb.addOutput(scripts[1], 9000), 1)
|
||||
assert.strictEqual(txb.addOutput(scripts[1], 9000), 1)
|
||||
})
|
||||
|
||||
it('add first output after signed first input with SIGHASH_NONE', function () {
|
||||
it('add first output after signed first input with SIGHASH_NONE', () => {
|
||||
txb.addInput(txHash, 0)
|
||||
txb.sign(0, keyPair, undefined, Transaction.SIGHASH_NONE)
|
||||
assert.equal(txb.addOutput(scripts[0], 2000), 0)
|
||||
assert.strictEqual(txb.addOutput(scripts[0], 2000), 0)
|
||||
})
|
||||
|
||||
it('add second output after signed first input with SIGHASH_SINGLE', function () {
|
||||
it('add second output after signed first input with SIGHASH_SINGLE', () => {
|
||||
txb.addInput(txHash, 0)
|
||||
txb.addOutput(scripts[0], 2000)
|
||||
txb.sign(0, keyPair, undefined, Transaction.SIGHASH_SINGLE)
|
||||
assert.equal(txb.addOutput(scripts[1], 9000), 1)
|
||||
assert.strictEqual(txb.addOutput(scripts[1], 9000), 1)
|
||||
})
|
||||
|
||||
it('add first output after signed first input with SIGHASH_SINGLE', function () {
|
||||
it('add first output after signed first input with SIGHASH_SINGLE', () => {
|
||||
txb.addInput(txHash, 0)
|
||||
txb.sign(0, keyPair, undefined, Transaction.SIGHASH_SINGLE)
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
txb.addOutput(scripts[0], 2000)
|
||||
}, /No, this would invalidate signatures/)
|
||||
})
|
||||
|
||||
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', () => {
|
||||
txb.addInput(txHash, 0)
|
||||
txb.addOutput(scripts[0], 2000)
|
||||
txb.sign(0, keyPair)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
txb.addOutput(scripts[1], 9000)
|
||||
}, /No, this would invalidate signatures/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('setLockTime', function () {
|
||||
it('throws if if there exist any scriptSigs', function () {
|
||||
describe('setLockTime', () => {
|
||||
it('throws if if there exist any scriptSigs', () => {
|
||||
const txb = new TransactionBuilder()
|
||||
txb.addInput(txHash, 0)
|
||||
txb.addOutput(scripts[0], 100)
|
||||
txb.sign(0, keyPair)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
txb.setLockTime(65535)
|
||||
}, /No, this would invalidate signatures/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('sign', function () {
|
||||
it('supports the alternative abstract interface { publicKey, sign }', function () {
|
||||
describe('sign', () => {
|
||||
it('supports the alternative abstract interface { publicKey, sign }', () => {
|
||||
const keyPair = {
|
||||
publicKey: ECPair.makeRandom({ rng: function () { return Buffer.alloc(32, 1) } }).publicKey,
|
||||
sign: function (hash) { return Buffer.alloc(64, 0x5f) }
|
||||
publicKey: ECPair.makeRandom({ rng: () => { return Buffer.alloc(32, 1) } }).publicKey,
|
||||
sign: hash => { return Buffer.alloc(64, 0x5f) }
|
||||
}
|
||||
|
||||
const txb = new TransactionBuilder()
|
||||
|
@ -335,16 +335,16 @@ describe('TransactionBuilder', function () {
|
|||
txb.addInput('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1)
|
||||
txb.addOutput('1111111111111111111114oLvT2', 100000)
|
||||
txb.sign(0, keyPair)
|
||||
assert.equal(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f02205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0121031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078fffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000')
|
||||
assert.strictEqual(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f02205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0121031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078fffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000')
|
||||
})
|
||||
|
||||
fixtures.invalid.sign.forEach(function (f) {
|
||||
it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), function () {
|
||||
fixtures.invalid.sign.forEach(f => {
|
||||
it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), () => {
|
||||
const txb = construct(f, true)
|
||||
|
||||
let threw = false
|
||||
f.inputs.forEach(function (input, index) {
|
||||
input.signs.forEach(function (sign) {
|
||||
f.inputs.forEach((input, index) => {
|
||||
input.signs.forEach(sign => {
|
||||
const keyPairNetwork = NETWORKS[sign.network || f.network]
|
||||
const keyPair2 = ECPair.fromWIF(sign.keyPair, keyPairNetwork)
|
||||
let redeemScript
|
||||
|
@ -359,7 +359,7 @@ describe('TransactionBuilder', function () {
|
|||
}
|
||||
|
||||
if (sign.throws) {
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript)
|
||||
}, new RegExp(f.exception))
|
||||
threw = true
|
||||
|
@ -369,14 +369,14 @@ describe('TransactionBuilder', function () {
|
|||
})
|
||||
})
|
||||
|
||||
assert.equal(threw, true)
|
||||
assert.strictEqual(threw, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('build', function () {
|
||||
fixtures.valid.build.forEach(function (f) {
|
||||
it('builds "' + f.description + '"', function () {
|
||||
describe('build', () => {
|
||||
fixtures.valid.build.forEach(f => {
|
||||
it('builds "' + f.description + '"', () => {
|
||||
const txb = construct(f)
|
||||
const tx = f.incomplete ? txb.buildIncomplete() : txb.build()
|
||||
|
||||
|
@ -385,10 +385,10 @@ describe('TransactionBuilder', function () {
|
|||
})
|
||||
|
||||
// TODO: remove duplicate test code
|
||||
fixtures.invalid.build.forEach(function (f) {
|
||||
describe('for ' + (f.description || f.exception), function () {
|
||||
it('throws ' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
fixtures.invalid.build.forEach(f => {
|
||||
describe('for ' + (f.description || f.exception), () => {
|
||||
it('throws ' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
let txb
|
||||
if (f.txHex) {
|
||||
txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex))
|
||||
|
@ -402,8 +402,8 @@ describe('TransactionBuilder', function () {
|
|||
|
||||
// if throws on incomplete too, enforce that
|
||||
if (f.incomplete) {
|
||||
it('throws ' + f.exception, function () {
|
||||
assert.throws(function () {
|
||||
it('throws ' + f.exception, () => {
|
||||
assert.throws(() => {
|
||||
let txb
|
||||
if (f.txHex) {
|
||||
txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex))
|
||||
|
@ -415,7 +415,7 @@ describe('TransactionBuilder', function () {
|
|||
}, new RegExp(f.exception))
|
||||
})
|
||||
} else {
|
||||
it('does not throw if buildIncomplete', function () {
|
||||
it('does not throw if buildIncomplete', () => {
|
||||
let txb
|
||||
if (f.txHex) {
|
||||
txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex))
|
||||
|
@ -429,7 +429,7 @@ describe('TransactionBuilder', function () {
|
|||
})
|
||||
})
|
||||
|
||||
it('for incomplete with 0 signatures', function () {
|
||||
it('for incomplete with 0 signatures', () => {
|
||||
const randomTxData = '0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000'
|
||||
const randomAddress = '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH'
|
||||
|
||||
|
@ -441,7 +441,7 @@ describe('TransactionBuilder', function () {
|
|||
assert(tx)
|
||||
})
|
||||
|
||||
it('for incomplete P2SH with 0 signatures', function () {
|
||||
it('for incomplete P2SH with 0 signatures', () => {
|
||||
const inp = Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a80400000017a91471a8ec07ff69c6c4fee489184c462a9b1b9237488700000000', 'hex') // arbitrary P2SH input
|
||||
const inpTx = Transaction.fromBuffer(inp)
|
||||
|
||||
|
@ -452,7 +452,7 @@ describe('TransactionBuilder', function () {
|
|||
txb.buildIncomplete()
|
||||
})
|
||||
|
||||
it('for incomplete P2WPKH with 0 signatures', function () {
|
||||
it('for incomplete P2WPKH with 0 signatures', () => {
|
||||
const inp = Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a8040000001600141a15805e1f4040c9f68ccc887fca2e63547d794b00000000', 'hex')
|
||||
const inpTx = Transaction.fromBuffer(inp)
|
||||
|
||||
|
@ -463,7 +463,7 @@ describe('TransactionBuilder', function () {
|
|||
txb.buildIncomplete()
|
||||
})
|
||||
|
||||
it('for incomplete P2WSH with 0 signatures', function () {
|
||||
it('for incomplete P2WSH with 0 signatures', () => {
|
||||
const inpTx = Transaction.fromBuffer(Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a80400000022002072df76fcc0b231b94bdf7d8c25d7eef4716597818d211e19ade7813bff7a250200000000', 'hex'))
|
||||
|
||||
const txb = new TransactionBuilder(NETWORKS.testnet)
|
||||
|
@ -474,17 +474,17 @@ describe('TransactionBuilder', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('multisig', function () {
|
||||
fixtures.valid.multisig.forEach(function (f) {
|
||||
it(f.description, function () {
|
||||
describe('multisig', () => {
|
||||
fixtures.valid.multisig.forEach(f => {
|
||||
it(f.description, () => {
|
||||
const network = NETWORKS[f.network]
|
||||
let txb = construct(f, true)
|
||||
let tx
|
||||
|
||||
f.inputs.forEach(function (input, i) {
|
||||
f.inputs.forEach((input, i) => {
|
||||
const redeemScript = bscript.fromASM(input.redeemScript)
|
||||
|
||||
input.signs.forEach(function (sign) {
|
||||
input.signs.forEach(sign => {
|
||||
// rebuild the transaction each-time after the first
|
||||
if (tx) {
|
||||
// manually override the scriptSig?
|
||||
|
@ -513,10 +513,10 @@ describe('TransactionBuilder', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('various edge case', function () {
|
||||
describe('various edge case', () => {
|
||||
const network = NETWORKS.testnet
|
||||
|
||||
it('should warn of high fee for segwit transaction based on VSize, not Size', function () {
|
||||
it('should warn of high fee for segwit transaction based on VSize, not Size', () => {
|
||||
const rawtx = '01000000000104fdaac89627208b4733484ca56bc291f4cf4fa8d7c5f29893c52b46788a0a' +
|
||||
'1df90000000000fffffffffdaac89627208b4733484ca56bc291f4cf4fa8d7c5f29893c52b46788a0a1df9' +
|
||||
'0100000000ffffffffa2ef7aaab316a3e5b5b0a78d1d35c774b95a079f9f0c762277a49caf1f26bca40000' +
|
||||
|
@ -538,12 +538,12 @@ describe('TransactionBuilder', function () {
|
|||
txb.__INPUTS[2].value = 248920
|
||||
txb.__INPUTS[3].value = 248920
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
txb.build()
|
||||
}, new RegExp('Transaction has absurd fees'))
|
||||
})
|
||||
|
||||
it('should classify witness inputs with witness = true during multisigning', function () {
|
||||
it('should classify witness inputs with witness = true during multisigning', () => {
|
||||
const keyPair = ECPair.fromWIF('cRAwuVuVSBZMPu7hdrYvMCZ8eevzmkExjFbaBLhqnDdrezxN3nTS', network)
|
||||
const witnessScript = Buffer.from('522102bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e22102d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea1952ae', 'hex')
|
||||
const redeemScript = Buffer.from('002024376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5af', 'hex')
|
||||
|
@ -558,13 +558,13 @@ describe('TransactionBuilder', function () {
|
|||
const tx = txb.buildIncomplete()
|
||||
|
||||
// Only input is segwit, so txid should be accurate with the final tx
|
||||
assert.equal(tx.getId(), 'f15d0a65b21b4471405b21a099f8b18e1ae4d46d55efbd0f4766cf11ad6cb821')
|
||||
assert.strictEqual(tx.getId(), 'f15d0a65b21b4471405b21a099f8b18e1ae4d46d55efbd0f4766cf11ad6cb821')
|
||||
|
||||
const txHex = tx.toHex()
|
||||
TransactionBuilder.fromTransaction(Transaction.fromHex(txHex))
|
||||
})
|
||||
|
||||
it('should handle badly pre-filled OP_0s', function () {
|
||||
it('should handle badly pre-filled OP_0s', () => {
|
||||
// OP_0 is used where a signature is missing
|
||||
const redeemScripSig = bscript.fromASM('OP_0 OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae')
|
||||
const redeemScript = bscript.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG')
|
||||
|
@ -580,11 +580,11 @@ describe('TransactionBuilder', function () {
|
|||
txb.sign(0, keyPair2, redeemScript)
|
||||
|
||||
const tx2 = txb.build()
|
||||
assert.equal(tx2.getId(), 'eab59618a564e361adef6d918bd792903c3d41bcf1220137364fb847880467f9')
|
||||
assert.equal(bscript.toASM(tx2.ins[0].script), 'OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae')
|
||||
assert.strictEqual(tx2.getId(), 'eab59618a564e361adef6d918bd792903c3d41bcf1220137364fb847880467f9')
|
||||
assert.strictEqual(bscript.toASM(tx2.ins[0].script), 'OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae')
|
||||
})
|
||||
|
||||
it('should not classify blank scripts as nonstandard', function () {
|
||||
it('should not classify blank scripts as nonstandard', () => {
|
||||
let txb = new TransactionBuilder()
|
||||
txb.setVersion(1)
|
||||
txb.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0)
|
||||
|
@ -596,14 +596,14 @@ describe('TransactionBuilder', function () {
|
|||
txb.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000)
|
||||
txb.sign(0, keyPair)
|
||||
const txId = txb.build().getId()
|
||||
assert.equal(txId, '54f097315acbaedb92a95455da3368eb45981cdae5ffbc387a9afc872c0f29b3')
|
||||
assert.strictEqual(txId, '54f097315acbaedb92a95455da3368eb45981cdae5ffbc387a9afc872c0f29b3')
|
||||
|
||||
// and, repeat
|
||||
txb = TransactionBuilder.fromTransaction(Transaction.fromHex(incomplete))
|
||||
txb.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000)
|
||||
txb.sign(0, keyPair)
|
||||
const txId2 = txb.build().getId()
|
||||
assert.equal(txId, txId2)
|
||||
assert.strictEqual(txId, txId2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -3,38 +3,38 @@ const assert = require('assert')
|
|||
const types = require('../src/types')
|
||||
const typeforce = require('typeforce')
|
||||
|
||||
describe('types', function () {
|
||||
describe('Buffer Hash160/Hash256', function () {
|
||||
describe('types', () => {
|
||||
describe('Buffer Hash160/Hash256', () => {
|
||||
const buffer20byte = Buffer.alloc(20)
|
||||
const buffer32byte = Buffer.alloc(32)
|
||||
|
||||
it('return true for valid size', function () {
|
||||
it('return true for valid size', () => {
|
||||
assert(types.Hash160bit(buffer20byte))
|
||||
assert(types.Hash256bit(buffer32byte))
|
||||
})
|
||||
|
||||
it('return true for oneOf', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
it('return true for oneOf', () => {
|
||||
assert.doesNotThrow(() => {
|
||||
typeforce(types.oneOf(types.Hash160bit, types.Hash256bit), buffer32byte)
|
||||
})
|
||||
|
||||
assert.doesNotThrow(function () {
|
||||
assert.doesNotThrow(() => {
|
||||
typeforce(types.oneOf(types.Hash256bit, types.Hash160bit), buffer32byte)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws for invalid size', function () {
|
||||
assert.throws(function () {
|
||||
it('throws for invalid size', () => {
|
||||
assert.throws(() => {
|
||||
types.Hash160bit(buffer32byte)
|
||||
}, /Expected Buffer\(Length: 20\), got Buffer\(Length: 32\)/)
|
||||
|
||||
assert.throws(function () {
|
||||
assert.throws(() => {
|
||||
types.Hash256bit(buffer20byte)
|
||||
}, /Expected Buffer\(Length: 32\), got Buffer\(Length: 20\)/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Satoshi', function () {
|
||||
describe('Satoshi', () => {
|
||||
[
|
||||
{ value: -1, result: false },
|
||||
{ value: 0, result: true },
|
||||
|
@ -42,8 +42,8 @@ describe('types', function () {
|
|||
{ value: 20999999 * 1e8, result: true },
|
||||
{ value: 21000000 * 1e8, result: true },
|
||||
{ value: 21000001 * 1e8, result: false }
|
||||
].forEach(function (f) {
|
||||
it('returns ' + f.result + ' for valid for ' + f.value, function () {
|
||||
].forEach(f => {
|
||||
it('returns ' + f.result + ' for valid for ' + f.value, () => {
|
||||
assert.strictEqual(types.Satoshi(f.value), f.result)
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue