From 44c13665c8f436c32d6a9036c585acfff75829fb Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 3 Jul 2018 22:33:35 +1000 Subject: [PATCH] payments: add p2data --- src/payments/index.js | 11 ++----- src/payments/p2data.js | 56 ++++++++++++++++++++++++++++++++ test/integration/transactions.js | 5 ++- 3 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 src/payments/p2data.js diff --git a/src/payments/index.js b/src/payments/index.js index 9e869f5..de3bec1 100644 --- a/src/payments/index.js +++ b/src/payments/index.js @@ -1,3 +1,4 @@ +const p2data = require('./p2data') const p2ms = require('./p2ms') const p2pk = require('./p2pk') const p2pkh = require('./p2pkh') @@ -5,15 +6,7 @@ const p2sh = require('./p2sh') const p2wpkh = require('./p2wpkh') const p2wsh = require('./p2wsh') -module.exports = { - p2ms: p2ms, - p2pk: p2pk, - p2pkh: p2pkh, - p2sh: p2sh, - p2wpkh: p2wpkh, - p2wsh: p2wsh -} +module.exports = { p2data, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh } // TODO -// OP_RETURN // witness commitment diff --git a/src/payments/p2data.js b/src/payments/p2data.js new file mode 100644 index 0000000..c636c80 --- /dev/null +++ b/src/payments/p2data.js @@ -0,0 +1,56 @@ +const lazy = require('./lazy') +const typef = require('typeforce') +const OPS = require('bitcoin-ops') + +const bscript = require('../script') +const BITCOIN_NETWORK = require('../networks').bitcoin + +function stacksEqual (a, b) { + if (a.length !== b.length) return false + + return a.every(function (x, i) { + return x.equals(b[i]) + }) +} + +// output: OP_RETURN ... +function p2data (a, opts) { + if ( + !a.data && + !a.output + ) throw new TypeError('Not enough data') + opts = opts || { validate: true } + + typef({ + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + data: typef.maybe(typef.arrayOf(typef.Buffer)) + }, a) + + const network = a.network || BITCOIN_NETWORK + const o = { network } + + lazy.prop(o, 'output', function () { + if (!a.data) return + return bscript.compile([OPS.OP_RETURN].concat(a.data)) + }) + lazy.prop(o, 'data', function () { + if (!a.output) return + return bscript.decompile(a.output).slice(1) + }) + + // extended validation + if (opts.validate) { + if (a.output) { + const chunks = bscript.decompile(a.output) + if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid') + if (!chunks.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid') + + if (a.data && !stacksEqual(a.data, o.data)) throw new TypeError('Data mismatch') + } + } + + return Object.assign(o, a) +} + +module.exports = p2data diff --git a/test/integration/transactions.js b/test/integration/transactions.js index 5bb1342..cec0839 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -91,10 +91,9 @@ describe('bitcoinjs-lib (transactions)', function () { const txb = new bitcoin.TransactionBuilder(regtest) const data = Buffer.from('bitcoinjs-lib', 'utf8') - const dataScript = require('../../src/templates/nulldata').output.encode([data]) - + const p2data = bitcoin.payments.p2data({ data: [data] }) txb.addInput(unspent.txId, unspent.vout) - txb.addOutput(dataScript, 1000) + txb.addOutput(p2data.output, 1000) txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e5) txb.sign(0, keyPair)