Add TX cache and addInput addOutput

This commit is contained in:
junderw 2019-07-04 13:33:08 +09:00
parent b28c96d228
commit f7e726a8eb
No known key found for this signature in database
GPG key ID: B256185D3A971908
5 changed files with 181 additions and 48 deletions

6
package-lock.json generated
View file

@ -200,9 +200,9 @@
} }
}, },
"bip174": { "bip174": {
"version": "0.0.12", "version": "0.0.13",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.12.tgz", "resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.13.tgz",
"integrity": "sha512-rYVuFTSCROv8iI07BhEddap+iXiFz2aiYEUSQR8rqv7JKWbMO2QQqCJMvr2E0df8wu5ySysd/CupIP4eG4ukqQ==" "integrity": "sha512-jWP7Lb27Nmbk6gaZKhJZOyk5LqRWs9z+R2xzgu3W8/iZXIIP2kcR6fh5lNg7GGOiWUaqanWC9rjrDVrBVbXKww=="
}, },
"bip32": { "bip32": {
"version": "2.0.3", "version": "2.0.3",

View file

@ -47,7 +47,7 @@
"dependencies": { "dependencies": {
"@types/node": "10.12.18", "@types/node": "10.12.18",
"bech32": "^1.1.2", "bech32": "^1.1.2",
"bip174": "0.0.12", "bip174": "0.0.13",
"bip32": "^2.0.3", "bip32": "^2.0.3",
"bip66": "^1.1.0", "bip66": "^1.1.0",
"bitcoin-ops": "^1.4.0", "bitcoin-ops": "^1.4.0",

View file

@ -3,6 +3,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
const bip174_1 = require('bip174'); const bip174_1 = require('bip174');
const utils_1 = require('bip174/src/lib/utils'); const utils_1 = require('bip174/src/lib/utils');
const address_1 = require('./address'); const address_1 = require('./address');
const bufferutils_1 = require('./bufferutils');
const crypto_1 = require('./crypto'); const crypto_1 = require('./crypto');
const networks_1 = require('./networks'); const networks_1 = require('./networks');
const payments = require('./payments'); const payments = require('./payments');
@ -12,28 +13,92 @@ const varuint = require('varuint-bitcoin');
class Psbt extends bip174_1.Psbt { class Psbt extends bip174_1.Psbt {
constructor(opts = {}) { constructor(opts = {}) {
super(); super();
// set defaults
this.setVersion(2); this.setVersion(2);
this.opts = Object.assign({}, DEFAULT_OPTS, opts); this.opts = Object.assign({}, DEFAULT_OPTS, opts);
// // TODO: figure out a way to use a Transaction Object instead of a Buffer this.__TX = transaction_1.Transaction.fromBuffer(this.globalMap.unsignedTx);
// // TODO: Caching, since .toBuffer() calls every time we get is lame. // set cache
// this.__TX = Transaction.fromBuffer(this.globalMap.unsignedTx!); const self = this;
// delete this.globalMap.unsignedTx; delete this.globalMap.unsignedTx;
// Object.defineProperty(this.globalMap, 'unsignedTx', { Object.defineProperty(this.globalMap, 'unsignedTx', {
// enumerable: true, enumerable: true,
// writable: false, get() {
// get(): Buffer { if (self.__TX_BUF_CACHE !== undefined) {
// return this.__TX.toBuffer(); return self.__TX_BUF_CACHE;
// } } else {
// }); self.__TX_BUF_CACHE = self.__TX.toBuffer();
return self.__TX_BUF_CACHE;
}
},
set(data) {
self.__TX_BUF_CACHE = data;
},
});
// Make data hidden when enumerating
const dpew = (obj, attr, enumerable, writable) =>
Object.defineProperty(obj, attr, {
enumerable,
writable,
});
dpew(this, '__TX', false, false);
dpew(this, '__TX_BUF_CACHE', false, true);
dpew(this, 'opts', false, true);
} }
addOutput(outputData, allowNoInput = false, transactionOutputAdder) { addInput(inputData) {
const self = this;
const inputAdder = (_inputData, txBuf) => {
if (
!txBuf ||
_inputData.hash === undefined ||
_inputData.index === undefined ||
(!Buffer.isBuffer(_inputData.hash) &&
typeof _inputData.hash !== 'string') ||
typeof _inputData.index !== 'number'
) {
throw new Error('Error adding input.');
}
const prevHash = Buffer.isBuffer(_inputData.hash)
? _inputData.hash
: bufferutils_1.reverseBuffer(Buffer.from(_inputData.hash, 'hex'));
self.__TX.ins.push({
hash: prevHash,
index: _inputData.index,
script: Buffer.alloc(0),
sequence:
_inputData.sequence || transaction_1.Transaction.DEFAULT_SEQUENCE,
witness: [],
});
console.log(self.__TX);
return self.__TX.toBuffer();
};
return super.addInput(inputData, inputAdder);
}
addOutput(outputData) {
const { address } = outputData; const { address } = outputData;
if (typeof address === 'string') { if (typeof address === 'string') {
const { network } = this.opts; const { network } = this.opts;
const script = address_1.toOutputScript(address, network); const script = address_1.toOutputScript(address, network);
outputData = Object.assign(outputData, { script }); outputData = Object.assign(outputData, { script });
} }
return super.addOutput(outputData, allowNoInput, transactionOutputAdder); const self = this;
const outputAdder = (_outputData, txBuf) => {
if (
!txBuf ||
_outputData.script === undefined ||
_outputData.value === undefined ||
!Buffer.isBuffer(_outputData.script) ||
typeof _outputData.value !== 'number'
) {
throw new Error('Error adding output.');
}
self.__TX.outs.push({
script: _outputData.script,
value: _outputData.value,
});
console.log(self.__TX);
return self.__TX.toBuffer();
};
return super.addOutput(outputData, true, outputAdder);
} }
extractTransaction() { extractTransaction() {
if (!this.inputs.every(isFinalized)) throw new Error('Not finalized'); if (!this.inputs.every(isFinalized)) throw new Error('Not finalized');

View file

@ -2,10 +2,12 @@ import { Psbt as PsbtBase } from 'bip174';
import { import {
PartialSig, PartialSig,
PsbtInput, PsbtInput,
TransactionInput,
TransactionOutput, TransactionOutput,
} from 'bip174/src/lib/interfaces'; } from 'bip174/src/lib/interfaces';
import { checkForInput } from 'bip174/src/lib/utils'; import { checkForInput } from 'bip174/src/lib/utils';
import { toOutputScript } from './address'; import { toOutputScript } from './address';
import { reverseBuffer } from './bufferutils';
import { hash160 } from './crypto'; import { hash160 } from './crypto';
import { Signer, SignerAsync } from './ecpair'; import { Signer, SignerAsync } from './ecpair';
import { bitcoin as btcNetwork, Network } from './networks'; import { bitcoin as btcNetwork, Network } from './networks';
@ -15,46 +17,111 @@ import { Transaction } from './transaction';
const varuint = require('varuint-bitcoin'); const varuint = require('varuint-bitcoin');
export class Psbt extends PsbtBase { export class Psbt extends PsbtBase {
// protected __TX: Transaction; private __TX: Transaction;
private __TX_BUF_CACHE?: Buffer;
private opts: PsbtOpts; private opts: PsbtOpts;
constructor(opts: PsbtOptsOptional = {}) { constructor(opts: PsbtOptsOptional = {}) {
super(); super();
// set defaults
this.setVersion(2); this.setVersion(2);
this.opts = Object.assign({}, DEFAULT_OPTS, opts); this.opts = Object.assign({}, DEFAULT_OPTS, opts);
// // TODO: figure out a way to use a Transaction Object instead of a Buffer this.__TX = Transaction.fromBuffer(this.globalMap.unsignedTx!);
// // TODO: Caching, since .toBuffer() calls every time we get is lame.
// this.__TX = Transaction.fromBuffer(this.globalMap.unsignedTx!); // set cache
// delete this.globalMap.unsignedTx; const self = this;
// Object.defineProperty(this.globalMap, 'unsignedTx', { delete this.globalMap.unsignedTx;
// enumerable: true, Object.defineProperty(this.globalMap, 'unsignedTx', {
// writable: false, enumerable: true,
// get(): Buffer { get(): Buffer {
// return this.__TX.toBuffer(); if (self.__TX_BUF_CACHE !== undefined) {
// } return self.__TX_BUF_CACHE;
// }); } else {
self.__TX_BUF_CACHE = self.__TX.toBuffer();
return self.__TX_BUF_CACHE;
}
},
set(data: Buffer): void {
self.__TX_BUF_CACHE = data;
},
});
// Make data hidden when enumerating
const dpew = (
obj: any,
attr: string,
enumerable: boolean,
writable: boolean,
): any =>
Object.defineProperty(obj, attr, {
enumerable,
writable,
});
dpew(this, '__TX', false, false);
dpew(this, '__TX_BUF_CACHE', false, true);
dpew(this, 'opts', false, true);
} }
addOutput(outputData: TransactionOutput, allowNoInput?: boolean): this; addInput(inputData: TransactionInput): this {
addOutput<T>( const self = this;
outputData: T, const inputAdder = (
allowNoInput?: boolean, _inputData: TransactionInput,
transactionOutputAdder?: (output: T, txBuffer: Buffer) => Buffer, txBuf: Buffer,
): this; ): Buffer => {
addOutput<T>( if (
outputData: T | TransactionOutput, !txBuf ||
allowNoInput: boolean = false, (_inputData as any).hash === undefined ||
transactionOutputAdder?: ( (_inputData as any).index === undefined ||
output: T | TransactionOutput, (!Buffer.isBuffer((_inputData as any).hash) &&
txBuffer: Buffer, typeof (_inputData as any).hash !== 'string') ||
) => Buffer, typeof (_inputData as any).index !== 'number'
): this { ) {
throw new Error('Error adding input.');
}
const prevHash = Buffer.isBuffer(_inputData.hash)
? _inputData.hash
: reverseBuffer(Buffer.from(_inputData.hash, 'hex'));
self.__TX.ins.push({
hash: prevHash,
index: _inputData.index,
script: Buffer.alloc(0),
sequence: _inputData.sequence || Transaction.DEFAULT_SEQUENCE,
witness: [],
});
console.log(self.__TX);
return self.__TX.toBuffer();
};
return super.addInput(inputData, inputAdder);
}
addOutput(outputData: TransactionOutput): this {
const { address } = outputData as any; const { address } = outputData as any;
if (typeof address === 'string') { if (typeof address === 'string') {
const { network } = this.opts; const { network } = this.opts;
const script = toOutputScript(address, network); const script = toOutputScript(address, network);
outputData = Object.assign(outputData, { script }); outputData = Object.assign(outputData, { script });
} }
return super.addOutput(outputData, allowNoInput, transactionOutputAdder); const self = this;
const outputAdder = (
_outputData: TransactionOutput,
txBuf: Buffer,
): Buffer => {
if (
!txBuf ||
(_outputData as any).script === undefined ||
(_outputData as any).value === undefined ||
!Buffer.isBuffer((_outputData as any).script) ||
typeof (_outputData as any).value !== 'number'
) {
throw new Error('Error adding output.');
}
self.__TX.outs.push({
script: (_outputData as any).script!,
value: _outputData.value,
});
console.log(self.__TX);
return self.__TX.toBuffer();
};
return super.addOutput(outputData, true, outputAdder);
} }
extractTransaction(): Transaction { extractTransaction(): Transaction {

9
types/psbt.d.ts vendored
View file

@ -1,14 +1,15 @@
/// <reference types="node" />
import { Psbt as PsbtBase } from 'bip174'; import { Psbt as PsbtBase } from 'bip174';
import { TransactionOutput } from 'bip174/src/lib/interfaces'; import { TransactionInput, TransactionOutput } from 'bip174/src/lib/interfaces';
import { Signer, SignerAsync } from './ecpair'; import { Signer, SignerAsync } from './ecpair';
import { Network } from './networks'; import { Network } from './networks';
import { Transaction } from './transaction'; import { Transaction } from './transaction';
export declare class Psbt extends PsbtBase { export declare class Psbt extends PsbtBase {
private __TX;
private __TX_BUF_CACHE?;
private opts; private opts;
constructor(opts?: PsbtOptsOptional); constructor(opts?: PsbtOptsOptional);
addOutput(outputData: TransactionOutput, allowNoInput?: boolean): this; addInput(inputData: TransactionInput): this;
addOutput<T>(outputData: T, allowNoInput?: boolean, transactionOutputAdder?: (output: T, txBuffer: Buffer) => Buffer): this; addOutput(outputData: TransactionOutput): this;
extractTransaction(): Transaction; extractTransaction(): Transaction;
finalizeAllInputs(): { finalizeAllInputs(): {
result: boolean; result: boolean;