Merge pull request #1135 from bitcoinjs/moretests
Add additional payments integration tests
This commit is contained in:
commit
d67e9758c7
4 changed files with 152 additions and 72 deletions
|
@ -232,6 +232,9 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
|
||||||
expanded.signatures = input.signatures
|
expanded.signatures = input.signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let signScript = witnessScript
|
||||||
|
if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
redeemScript,
|
redeemScript,
|
||||||
redeemScriptType: SCRIPT_TYPES.P2WSH,
|
redeemScriptType: SCRIPT_TYPES.P2WSH,
|
||||||
|
@ -243,7 +246,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
|
||||||
prevOutScript: p2sh.output,
|
prevOutScript: p2sh.output,
|
||||||
|
|
||||||
hasWitness: true,
|
hasWitness: true,
|
||||||
signScript: witnessScript,
|
signScript,
|
||||||
signType: expanded.type,
|
signType: expanded.type,
|
||||||
|
|
||||||
pubkeys: expanded.pubkeys,
|
pubkeys: expanded.pubkeys,
|
||||||
|
@ -303,6 +306,9 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
|
||||||
expanded.signatures = input.signatures
|
expanded.signatures = input.signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let signScript = witnessScript
|
||||||
|
if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2WSH(P2WPKH) is a consensus failure')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
witnessScript,
|
witnessScript,
|
||||||
witnessScriptType: expanded.type,
|
witnessScriptType: expanded.type,
|
||||||
|
@ -311,7 +317,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
|
||||||
prevOutScript: p2wsh.output,
|
prevOutScript: p2wsh.output,
|
||||||
|
|
||||||
hasWitness: true,
|
hasWitness: true,
|
||||||
signScript: witnessScript,
|
signScript,
|
||||||
signType: expanded.type,
|
signType: expanded.type,
|
||||||
|
|
||||||
pubkeys: expanded.pubkeys,
|
pubkeys: expanded.pubkeys,
|
||||||
|
|
|
@ -4,6 +4,7 @@ const dhttp = require('dhttp/200')
|
||||||
|
|
||||||
const APIPASS = process.env.APIPASS || 'satoshi'
|
const APIPASS = process.env.APIPASS || 'satoshi'
|
||||||
const APIURL = 'https://api.dcousens.cloud/1'
|
const APIURL = 'https://api.dcousens.cloud/1'
|
||||||
|
const NETWORK = bitcoin.networks.testnet
|
||||||
|
|
||||||
function broadcast (txHex, callback) {
|
function broadcast (txHex, callback) {
|
||||||
dhttp({
|
dhttp({
|
||||||
|
@ -37,7 +38,35 @@ function faucet (address, value, callback) {
|
||||||
unspents(address, function (err, results) {
|
unspents(address, function (err, results) {
|
||||||
if (err) return callback(err)
|
if (err) return callback(err)
|
||||||
|
|
||||||
callback(null, results.filter(x => x.txId === txId).pop())
|
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) {
|
||||||
|
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 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)
|
||||||
|
|
||||||
|
return callback(null, {
|
||||||
|
txId: txv.getId(),
|
||||||
|
vout: 0,
|
||||||
|
value
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -78,14 +107,15 @@ function randomAddress () {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
broadcast: broadcast,
|
broadcast,
|
||||||
faucet: faucet,
|
faucet,
|
||||||
fetch: fetch,
|
faucetComplex,
|
||||||
height: height,
|
fetch,
|
||||||
mine: mine,
|
height,
|
||||||
network: bitcoin.networks.testnet,
|
mine,
|
||||||
unspents: unspents,
|
network: NETWORK,
|
||||||
verify: verify,
|
unspents,
|
||||||
randomAddress: randomAddress,
|
verify,
|
||||||
|
randomAddress,
|
||||||
RANDOM_ADDRESS: randomAddress()
|
RANDOM_ADDRESS: randomAddress()
|
||||||
}
|
}
|
||||||
|
|
72
test/integration/payments.js
Normal file
72
test/integration/payments.js
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/* global describe, it */
|
||||||
|
|
||||||
|
const bitcoin = require('../../')
|
||||||
|
|
||||||
|
const regtestUtils = require('./_regtest')
|
||||||
|
const NETWORK = regtestUtils.network
|
||||||
|
const keyPairs = [
|
||||||
|
bitcoin.ECPair.makeRandom({ network: NETWORK }),
|
||||||
|
bitcoin.ECPair.makeRandom({ network: NETWORK })
|
||||||
|
]
|
||||||
|
|
||||||
|
function buildAndSign (depends, prevOutput, redeemScript, witnessScript, done) {
|
||||||
|
regtestUtils.faucetComplex(prevOutput, 5e4, (err, unspent) => {
|
||||||
|
if (err) return done(err)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
regtestUtils.broadcast(txb.build().toHex(), done)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
;['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach((k) => {
|
||||||
|
const fixtures = require('../fixtures/' + k)
|
||||||
|
const { depends } = fixtures.dynamic
|
||||||
|
const fn = bitcoin.payments[k]
|
||||||
|
|
||||||
|
const base = {}
|
||||||
|
if (depends.pubkey) base.pubkey = keyPairs[0].publicKey
|
||||||
|
if (depends.pubkeys) base.pubkeys = keyPairs.map(x => x.publicKey)
|
||||||
|
if (depends.m) base.m = base.pubkeys.length
|
||||||
|
|
||||||
|
const { output } = fn(base)
|
||||||
|
if (!output) throw new TypeError('Missing output')
|
||||||
|
|
||||||
|
describe('bitcoinjs-lib (payments - ' + k + ')', function () {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
it('can broadcast as an output, and be spent as an input', (done) => {
|
||||||
|
buildAndSign(depends, output, null, null, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can (as P2SH(' + k + ')) broadcast as an output, and be spent as an input', (done) => {
|
||||||
|
const p2sh = bitcoin.payments.p2sh({ redeem: { output }, network: NETWORK })
|
||||||
|
buildAndSign(depends, p2sh.output, p2sh.redeem.output, null, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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) => {
|
||||||
|
const p2wsh = bitcoin.payments.p2wsh({ redeem: { output }, network: NETWORK })
|
||||||
|
buildAndSign(depends, p2wsh.output, null, p2wsh.redeem.output, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can (as P2SH(P2WSH(' + k + '))) broadcast as an output, and be spent as an input', (done) => {
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -171,33 +171,20 @@ describe('bitcoinjs-lib (transactions)', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input (via a P2SH(P2WPKH) transaction)', function (done) {
|
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', function (done) {
|
||||||
this.timeout(30000)
|
this.timeout(30000)
|
||||||
|
|
||||||
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||||
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: regtest })
|
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: regtest })
|
||||||
|
|
||||||
// prepare a P2SH(P2WPKH) faucet transaction, as Bitcoin-core doesn't support bare P2WPKH outputs (...yet)
|
regtestUtils.faucetComplex(p2wpkh.address, 5e4, function (err, unspent) {
|
||||||
const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network: regtest })
|
|
||||||
|
|
||||||
regtestUtils.faucet(p2sh.address, 10e4, function (err, unspent) {
|
|
||||||
if (err) return done(err)
|
|
||||||
|
|
||||||
const txvb = new bitcoin.TransactionBuilder(regtest)
|
|
||||||
txvb.addInput(unspent.txId, unspent.vout)
|
|
||||||
txvb.addOutput(p2wpkh.address, 6e4) // funds a P2WPKH address
|
|
||||||
txvb.sign(0, keyPair, p2sh.redeem.output, null, unspent.value)
|
|
||||||
const txv = txvb.build()
|
|
||||||
|
|
||||||
// build and broadcast (the via transaction) to the Bitcoin RegTest network
|
|
||||||
regtestUtils.broadcast(txv.toHex(), function (err) {
|
|
||||||
if (err) return done(err)
|
if (err) return done(err)
|
||||||
|
|
||||||
// XXX: build the Transaction w/ a P2WPKH input
|
// XXX: build the Transaction w/ a P2WPKH input
|
||||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||||
txb.addInput(txv.getId(), 0, null, p2wpkh.output) // NOTE: provide the prevOutScript!
|
txb.addInput(unspent.txId, unspent.vout, null, p2wpkh.output) // NOTE: provide the prevOutScript!
|
||||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||||
txb.sign(0, keyPair, null, null, 6e4) // NOTE: no redeem script
|
txb.sign(0, keyPair, null, null, unspent.value) // NOTE: no redeem script
|
||||||
const tx = txb.build()
|
const tx = txb.build()
|
||||||
|
|
||||||
// build and broadcast (the P2WPKH transaction) to the Bitcoin RegTest network
|
// build and broadcast (the P2WPKH transaction) to the Bitcoin RegTest network
|
||||||
|
@ -213,36 +200,22 @@ describe('bitcoinjs-lib (transactions)', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input (via a P2SH(P2PK) transaction)', function (done) {
|
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', function (done) {
|
||||||
this.timeout(30000)
|
this.timeout(30000)
|
||||||
|
|
||||||
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
const keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
|
||||||
const p2pk = bitcoin.payments.p2pk({ pubkey: keyPair.publicKey, network: regtest })
|
const p2pk = bitcoin.payments.p2pk({ pubkey: keyPair.publicKey, network: regtest })
|
||||||
const p2wsh = bitcoin.payments.p2wsh({ redeem: p2pk, network: regtest })
|
const p2wsh = bitcoin.payments.p2wsh({ redeem: p2pk, network: regtest })
|
||||||
|
|
||||||
// prepare a P2SH(P2PK) faucet transaction, as Bitcoin-core doesn't support bare P2WSH outputs (...yet)
|
regtestUtils.faucetComplex(p2wsh.address, 5e4, function (err, unspent) {
|
||||||
const p2sh = bitcoin.payments.p2sh({ redeem: p2pk, network: regtest })
|
|
||||||
|
|
||||||
regtestUtils.faucet(p2sh.address, 10e4, function (err, unspent) {
|
|
||||||
if (err) return done(err)
|
|
||||||
|
|
||||||
const txvb = new bitcoin.TransactionBuilder(regtest)
|
|
||||||
txvb.addInput(unspent.txId, unspent.vout)
|
|
||||||
txvb.addOutput(p2wsh.address, 6e4) // funds a P2WPKH address
|
|
||||||
txvb.sign(0, keyPair, p2sh.redeem.output)
|
|
||||||
const txv = txvb.build()
|
|
||||||
|
|
||||||
// build and broadcast (the via transaction) to the Bitcoin RegTest network
|
|
||||||
regtestUtils.broadcast(txv.toHex(), function (err) {
|
|
||||||
if (err) return done(err)
|
if (err) return done(err)
|
||||||
|
|
||||||
// XXX: build the Transaction w/ a P2WSH input
|
// XXX: build the Transaction w/ a P2WSH input
|
||||||
const txb = new bitcoin.TransactionBuilder(regtest)
|
const txb = new bitcoin.TransactionBuilder(regtest)
|
||||||
txb.addInput(txv.getId(), 0, null, p2wsh.output) // NOTE: provide the prevOutScript!
|
txb.addInput(unspent.txId, unspent.vout, null, p2wsh.output) // NOTE: provide the prevOutScript!
|
||||||
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
|
||||||
txb.sign(0, keyPair, null, null, 6e4, p2wsh.redeem.output) // NOTE: provide a witnessScript!
|
txb.sign(0, keyPair, null, null, 5e4, p2wsh.redeem.output) // NOTE: provide a witnessScript!
|
||||||
const tx = txb.build()
|
const tx = txb.build()
|
||||||
|
|
||||||
// build and broadcast (the P2WSH transaction) to the Bitcoin RegTest network
|
// build and broadcast (the P2WSH transaction) to the Bitcoin RegTest network
|
||||||
|
@ -258,7 +231,6 @@ describe('bitcoinjs-lib (transactions)', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
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', function (done) {
|
||||||
this.timeout(50000)
|
this.timeout(50000)
|
||||||
|
|
Loading…
Reference in a new issue