From cd84ab90e45072502997364f95a7ee70805aaebd Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Thu, 6 Jun 2019 17:32:09 +0700 Subject: [PATCH] Move toPsbtString() to TransactionBuilderV2 not Transaction --- src/transaction.js | 24 ------------------- src/transaction_builder_v2.js | 23 ++++++++++++++++++ test/fixtures/transaction.json | 1 - test/fixtures/transaction_builder.json | 8 +++++++ test/transaction.js | 19 --------------- test/transaction_builder_v2.js | 11 +++++++++ ts_src/transaction.ts | 31 ------------------------ ts_src/transaction_builder_v2.ts | 33 +++++++++++++++++++++++++- types/transaction.d.ts | 1 - types/transaction_builder_v2.d.ts | 1 + 10 files changed, 75 insertions(+), 77 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index d29aff3..c4e6506 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,13 +1,11 @@ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); -const bip174_1 = require('bip174'); const bufferutils = require('./bufferutils'); const bufferutils_1 = require('./bufferutils'); const bcrypto = require('./crypto'); const bscript = require('./script'); const script_1 = require('./script'); const types = require('./types'); -const reverse = require('buffer-reverse'); const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); function varSliceSize(someScript) { @@ -380,28 +378,6 @@ class Transaction { toHex() { return this.toBuffer(undefined, undefined).toString('hex'); } - toPsbtString() { - const outputs = this.outs.map(output => ({ - script: output.script.toString('hex'), - tokens: output.value, - })); - const utxos = this.ins.map(input => ({ - id: reverse(input.hash).toString('hex'), - vout: input.index, - sequence: input.sequence, - })); - const timelock = this.locktime; - const { version } = this; - const { psbt } = bip174_1.createPsbt({ - outputs, - utxos, - timelock, - version, - }); - // TODO: Add signature data to PSBT - // TODO: Merge with imported PSBT if exists so we don't lose data - return Buffer.from(psbt, 'hex').toString('base64'); - } setInputScript(index, scriptSig) { typeforce(types.tuple(types.Number, types.Buffer), arguments); this.ins[index].script = scriptSig; diff --git a/src/transaction_builder_v2.js b/src/transaction_builder_v2.js index d33a1a3..d46aae5 100644 --- a/src/transaction_builder_v2.js +++ b/src/transaction_builder_v2.js @@ -12,6 +12,7 @@ const bscript = require('./script'); const script_1 = require('./script'); const transaction_1 = require('./transaction'); const types = require('./types'); +const reverse = require('buffer-reverse'); const typeforce = require('typeforce'); const SCRIPT_TYPES = classify.types; function txIsString(tx) { @@ -223,6 +224,28 @@ class TransactionBuilderV2 { }); if (!signed) throw new Error('Key pair cannot sign for this input'); } + toPsbtString() { + const outputs = this.__TX.outs.map(output => ({ + script: output.script.toString('hex'), + tokens: output.value, + })); + const utxos = this.__TX.ins.map(input => ({ + id: reverse(input.hash).toString('hex'), + vout: input.index, + sequence: input.sequence, + })); + const timelock = this.__TX.locktime; + const { version } = this.__TX; + const { psbt } = bip174_1.createPsbt({ + outputs, + utxos, + timelock, + version, + }); + // TODO: Add signature data to PSBT + // TODO: Merge with imported PSBT if exists so we don't lose data + return Buffer.from(psbt, 'hex').toString('base64'); + } __addInputUnsafe(txHash, vout, options) { if (transaction_1.Transaction.isCoinbaseHash(txHash)) { throw new Error('coinbase inputs not supported'); diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json index 76d8842..a70b5a8 100644 --- a/test/fixtures/transaction.json +++ b/test/fixtures/transaction.json @@ -6,7 +6,6 @@ "id": "af2cac1e0e33d896d9d0751d66fcb2fa54b737c7a13199281fb57e4f497bb652", "hash": "52b67b494f7eb51f289931a1c737b754fab2fc661d75d0d996d8330e1eac2caf", "hex": "0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300", - "psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAAAA", "raw": { "version": 2, "locktime": 1257139, diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index bb7bb37..8a97313 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -1526,6 +1526,14 @@ "txHex": "0200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac00000000" } ], + "toPsbtString": [ + { + "description": "Standard unsigned transaction (1:2)", + "incomplete": false, + "psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAAAA", + "txHex": "0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300" + } + ], "fromTransaction": [ { "description": "Transaction w/ P2SH(P2MS 2/2) -> OP_RETURN | 1 OP_0 fixes to 2 OP_0, no signatures", diff --git a/test/transaction.js b/test/transaction.js index 5cf206d..5146501 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -121,25 +121,6 @@ describe('Transaction', () => { }) }) - describe('toPsbtString', () => { - fixtures.valid - .filter(f => f.psbt) - .forEach(f => { - it('exports ' + f.description + ' (' + f.id + ')', () => { - const actual = fromRaw(f.raw, true) - assert.strictEqual(actual.toPsbtString(), f.psbt) - }) - - it('doesn\'t loose transaction data when cycling through toPsbtString() => fromPsbtString(), with: ' + f.description + ' (' + f.id + ')', () => { - const tx = fromRaw(f.raw, true) - const psbt = tx.toPsbtString() - const txbfromPsbtString = TransactionBuilderV2.fromPsbtString(psbt) - const txfromPsbtString = f.incomplete ? txbfromPsbtString.buildIncomplete() : txbfromPsbtString.build() - assert.strictEqual(tx.toHex(), txfromPsbtString.toHex()) - }) - }) - }) - describe('hasWitnesses', () => { fixtures.valid.forEach(f => { it('detects if the transaction has witnesses: ' + (f.whex ? 'true' : 'false'), () => { diff --git a/test/transaction_builder_v2.js b/test/transaction_builder_v2.js index ae05a67..873f60c 100644 --- a/test/transaction_builder_v2.js +++ b/test/transaction_builder_v2.js @@ -198,6 +198,17 @@ describe('TransactionBuilderV2', () => { }) }) + describe('toPsbtString', () => { + fixtures.valid.toPsbtString.forEach(f => { + it('returns a PSBT string, with ' + f.description, () => { + const tx = Transaction.fromHex(f.txHex) + const txb = TransactionBuilderV2.fromTransaction(tx) + + assert.strictEqual(txb.toPsbtString(), f.psbt) + }) + }) + }) + describe('addInput', () => { let txb beforeEach(() => { diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index ae57246..218d004 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -1,4 +1,3 @@ -import { createPsbt } from 'bip174'; import * as bufferutils from './bufferutils'; import { reverseBuffer } from './bufferutils'; import * as bcrypto from './crypto'; @@ -6,7 +5,6 @@ import * as bscript from './script'; import { OPS as opcodes } from './script'; import * as types from './types'; -const reverse = require('buffer-reverse'); const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); @@ -503,35 +501,6 @@ export class Transaction { return this.toBuffer(undefined, undefined).toString('hex'); } - toPsbtString(): string { - const outputs = this.outs.map(output => ({ - script: output.script.toString('hex'), - tokens: (output as Output).value, - })); - - const utxos = this.ins.map(input => ({ - id: reverse(input.hash).toString('hex'), - vout: input.index, - sequence: input.sequence, - })); - - const timelock = this.locktime; - const { version } = this; - - const { psbt } = createPsbt({ - outputs, - utxos, - timelock, - version, - }); - - // TODO: Add signature data to PSBT - - // TODO: Merge with imported PSBT if exists so we don't lose data - - return Buffer.from(psbt, 'hex').toString('base64'); - } - setInputScript(index: number, scriptSig: Buffer): void { typeforce(types.tuple(types.Number, types.Buffer), arguments); diff --git a/ts_src/transaction_builder_v2.ts b/ts_src/transaction_builder_v2.ts index 1b9e171..aeedc89 100644 --- a/ts_src/transaction_builder_v2.ts +++ b/ts_src/transaction_builder_v2.ts @@ -1,4 +1,4 @@ -import { decodePsbt } from 'bip174'; +import { createPsbt, decodePsbt } from 'bip174'; import * as baddress from './address'; import { reverseBuffer } from './bufferutils'; import * as classify from './classify'; @@ -13,6 +13,8 @@ import * as bscript from './script'; import { decompile, OPS as ops } from './script'; import { Output, Transaction } from './transaction'; import * as types from './types'; + +const reverse = require('buffer-reverse'); const typeforce = require('typeforce'); const SCRIPT_TYPES = classify.types; @@ -334,6 +336,35 @@ export class TransactionBuilderV2 { if (!signed) throw new Error('Key pair cannot sign for this input'); } + toPsbtString(): string { + const outputs = this.__TX.outs.map(output => ({ + script: output.script.toString('hex'), + tokens: (output as Output).value, + })); + + const utxos = this.__TX.ins.map(input => ({ + id: reverse(input.hash).toString('hex'), + vout: input.index, + sequence: input.sequence, + })); + + const timelock = this.__TX.locktime; + const { version } = this.__TX; + + const { psbt } = createPsbt({ + outputs, + utxos, + timelock, + version, + }); + + // TODO: Add signature data to PSBT + + // TODO: Merge with imported PSBT if exists so we don't lose data + + return Buffer.from(psbt, 'hex').toString('base64'); + } + private __addInputUnsafe( txHash: Buffer, vout: number, diff --git a/types/transaction.d.ts b/types/transaction.d.ts index 3e961bc..9bdba19 100644 --- a/types/transaction.d.ts +++ b/types/transaction.d.ts @@ -52,7 +52,6 @@ export declare class Transaction { getId(): string; toBuffer(buffer?: Buffer, initialOffset?: number): Buffer; toHex(): string; - toPsbtString(): string; setInputScript(index: number, scriptSig: Buffer): void; setWitness(index: number, witness: Buffer[]): void; private __byteLength; diff --git a/types/transaction_builder_v2.d.ts b/types/transaction_builder_v2.d.ts index 4e8b8bc..ebce07d 100644 --- a/types/transaction_builder_v2.d.ts +++ b/types/transaction_builder_v2.d.ts @@ -20,6 +20,7 @@ export declare class TransactionBuilderV2 { build(): Transaction; buildIncomplete(): Transaction; sign(vin: number, keyPair: ECPairInterface, redeemScript?: Buffer, hashType?: number, witnessValue?: number, witnessScript?: Buffer): void; + toPsbtString(): string; private __addInputUnsafe; private __build; private __canModifyInputs;