Add TX cache and addInput addOutput
This commit is contained in:
parent
b28c96d228
commit
f7e726a8eb
5 changed files with 181 additions and 48 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
91
src/psbt.js
91
src/psbt.js
|
@ -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');
|
||||||
|
|
121
ts_src/psbt.ts
121
ts_src/psbt.ts
|
@ -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
9
types/psbt.d.ts
vendored
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue