Browse Source

Move toPsbtString() to TransactionBuilderV2 not Transaction

psbt-support
Luke Childs 6 years ago
parent
commit
cd84ab90e4
  1. 24
      src/transaction.js
  2. 23
      src/transaction_builder_v2.js
  3. 1
      test/fixtures/transaction.json
  4. 8
      test/fixtures/transaction_builder.json
  5. 19
      test/transaction.js
  6. 11
      test/transaction_builder_v2.js
  7. 31
      ts_src/transaction.ts
  8. 33
      ts_src/transaction_builder_v2.ts
  9. 1
      types/transaction.d.ts
  10. 1
      types/transaction_builder_v2.d.ts

24
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;

23
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');

1
test/fixtures/transaction.json

@ -6,7 +6,6 @@
"id": "af2cac1e0e33d896d9d0751d66fcb2fa54b737c7a13199281fb57e4f497bb652",
"hash": "52b67b494f7eb51f289931a1c737b754fab2fc661d75d0d996d8330e1eac2caf",
"hex": "0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300",
"psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAAAA",
"raw": {
"version": 2,
"locktime": 1257139,

8
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",

19
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'), () => {

11
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(() => {

31
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);

33
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,

1
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;

1
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;

Loading…
Cancel
Save