Remove unnecessary extra Transaction Buffer parsing

This commit is contained in:
junderw 2019-07-04 14:33:36 +09:00
parent b98761a283
commit 5b5daf84dd
No known key found for this signature in database
GPG key ID: B256185D3A971908
3 changed files with 108 additions and 24 deletions

View file

@ -11,6 +11,39 @@ const bscript = require('./script');
const transaction_1 = require('./transaction');
const varuint = require('varuint-bitcoin');
class Psbt extends bip174_1.Psbt {
static fromTransaction(txBuf) {
const tx = transaction_1.Transaction.fromBuffer(txBuf);
const psbt = new this();
psbt.__TX = tx;
let inputCount = tx.ins.length;
let outputCount = tx.outs.length;
while (inputCount > 0) {
psbt.inputs.push({
keyVals: [],
});
inputCount--;
}
while (outputCount > 0) {
psbt.outputs.push({
keyVals: [],
});
outputCount--;
}
return psbt;
}
static fromBuffer(buffer) {
let tx;
const txCountGetter = txBuf => {
tx = transaction_1.Transaction.fromBuffer(txBuf);
return {
inputCount: tx.ins.length,
outputCount: tx.outs.length,
};
};
const psbt = super.fromBuffer(buffer, txCountGetter);
psbt.__TX = tx;
return psbt;
}
constructor(opts = {}) {
super();
// set defaults
@ -40,7 +73,7 @@ class Psbt extends bip174_1.Psbt {
enumerable,
writable,
});
dpew(this, '__TX', false, false);
dpew(this, '__TX', false, true);
dpew(this, '__TX_BUF_CACHE', false, true);
dpew(this, 'opts', false, true);
}
@ -112,7 +145,7 @@ class Psbt extends bip174_1.Psbt {
}
extractTransaction() {
if (!this.inputs.every(isFinalized)) throw new Error('Not finalized');
const tx = transaction_1.Transaction.fromBuffer(this.globalMap.unsignedTx);
const tx = this.__TX.clone();
this.inputs.forEach((input, idx) => {
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
if (input.finalScriptWitness) {
@ -138,7 +171,7 @@ class Psbt extends bip174_1.Psbt {
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
inputIndex,
input,
this.globalMap.unsignedTx,
this.__TX,
);
if (!script) return false;
const scriptType = classifyScript(script);
@ -166,7 +199,7 @@ class Psbt extends bip174_1.Psbt {
this.inputs,
inputIndex,
keyPair.publicKey,
this.globalMap.unsignedTx,
this.__TX,
);
const partialSig = {
pubkey: keyPair.publicKey,
@ -182,7 +215,7 @@ class Psbt extends bip174_1.Psbt {
this.inputs,
inputIndex,
keyPair.publicKey,
this.globalMap.unsignedTx,
this.__TX,
);
Promise.resolve(keyPair.sign(hash)).then(signature => {
const partialSig = {
@ -202,9 +235,13 @@ const DEFAULT_OPTS = {
function isFinalized(input) {
return !!input.finalScriptSig || !!input.finalScriptWitness;
}
function getHashAndSighashType(inputs, inputIndex, pubkey, txBuf) {
function getHashAndSighashType(inputs, inputIndex, pubkey, unsignedTx) {
const input = utils_1.checkForInput(inputs, inputIndex);
const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf);
const { hash, sighashType, script } = getHashForSig(
inputIndex,
input,
unsignedTx,
);
checkScriptForPubkey(pubkey, script);
return {
hash,
@ -322,8 +359,7 @@ function checkScriptForPubkey(pubkey, script) {
);
}
}
const getHashForSig = (inputIndex, input, txBuf) => {
const unsignedTx = transaction_1.Transaction.fromBuffer(txBuf);
const getHashForSig = (inputIndex, input, unsignedTx) => {
const sighashType =
input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
let hash;
@ -442,7 +478,7 @@ const classifyScript = script => {
if (isP2PK(script)) return 'pubkey';
return 'nonstandard';
};
function getScriptFromInput(inputIndex, input, _unsignedTx) {
function getScriptFromInput(inputIndex, input, unsignedTx) {
const res = {
script: null,
isSegwit: false,
@ -454,7 +490,6 @@ function getScriptFromInput(inputIndex, input, _unsignedTx) {
res.isP2SH = true;
res.script = input.redeemScript;
} else {
const unsignedTx = transaction_1.Transaction.fromBuffer(_unsignedTx);
const nonWitnessUtxoTx = transaction_1.Transaction.fromBuffer(
input.nonWitnessUtxo,
);

View file

@ -17,6 +17,50 @@ import { Transaction } from './transaction';
const varuint = require('varuint-bitcoin');
export class Psbt extends PsbtBase {
static fromTransaction<T extends typeof PsbtBase>(
this: T,
txBuf: Buffer,
): InstanceType<T> {
const tx = Transaction.fromBuffer(txBuf);
const psbt = new this() as Psbt;
psbt.__TX = tx;
let inputCount = tx.ins.length;
let outputCount = tx.outs.length;
while (inputCount > 0) {
psbt.inputs.push({
keyVals: [],
});
inputCount--;
}
while (outputCount > 0) {
psbt.outputs.push({
keyVals: [],
});
outputCount--;
}
return psbt as InstanceType<T>;
}
static fromBuffer<T extends typeof PsbtBase>(
this: T,
buffer: Buffer,
): InstanceType<T> {
let tx: Transaction | undefined;
const txCountGetter = (
txBuf: Buffer,
): {
inputCount: number;
outputCount: number;
} => {
tx = Transaction.fromBuffer(txBuf);
return {
inputCount: tx.ins.length,
outputCount: tx.outs.length,
};
};
const psbt = super.fromBuffer(buffer, txCountGetter) as Psbt;
psbt.__TX = tx!;
return psbt as InstanceType<T>;
}
private __TX: Transaction;
private __TX_BUF_CACHE?: Buffer;
private opts: PsbtOpts;
@ -56,7 +100,7 @@ export class Psbt extends PsbtBase {
enumerable,
writable,
});
dpew(this, '__TX', false, false);
dpew(this, '__TX', false, true);
dpew(this, '__TX_BUF_CACHE', false, true);
dpew(this, 'opts', false, true);
}
@ -138,7 +182,7 @@ export class Psbt extends PsbtBase {
extractTransaction(): Transaction {
if (!this.inputs.every(isFinalized)) throw new Error('Not finalized');
const tx = Transaction.fromBuffer(this.globalMap.unsignedTx!);
const tx = this.__TX.clone();
this.inputs.forEach((input, idx) => {
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
if (input.finalScriptWitness) {
@ -169,7 +213,7 @@ export class Psbt extends PsbtBase {
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
inputIndex,
input,
this.globalMap.unsignedTx!,
this.__TX,
);
if (!script) return false;
@ -195,14 +239,14 @@ export class Psbt extends PsbtBase {
return true;
}
signInput(inputIndex: number, keyPair: Signer): Psbt {
signInput(inputIndex: number, keyPair: Signer): this {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
const { hash, sighashType } = getHashAndSighashType(
this.inputs,
inputIndex,
keyPair.publicKey,
this.globalMap.unsignedTx!,
this.__TX,
);
const partialSig = {
@ -222,7 +266,7 @@ export class Psbt extends PsbtBase {
this.inputs,
inputIndex,
keyPair.publicKey,
this.globalMap.unsignedTx!,
this.__TX,
);
Promise.resolve(keyPair.sign(hash)).then(signature => {
@ -269,13 +313,17 @@ function getHashAndSighashType(
inputs: PsbtInput[],
inputIndex: number,
pubkey: Buffer,
txBuf: Buffer,
unsignedTx: Transaction,
): {
hash: Buffer;
sighashType: number;
} {
const input = checkForInput(inputs, inputIndex);
const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf);
const { hash, sighashType, script } = getHashForSig(
inputIndex,
input,
unsignedTx,
);
checkScriptForPubkey(pubkey, script);
return {
hash,
@ -424,9 +472,8 @@ interface HashForSigData {
const getHashForSig = (
inputIndex: number,
input: PsbtInput,
txBuf: Buffer,
unsignedTx: Transaction,
): HashForSigData => {
const unsignedTx = Transaction.fromBuffer(txBuf);
const sighashType = input.sighashType || Transaction.SIGHASH_ALL;
let hash: Buffer;
let script: Buffer;
@ -571,7 +618,7 @@ interface GetScriptReturn {
function getScriptFromInput(
inputIndex: number,
input: PsbtInput,
_unsignedTx: Buffer,
unsignedTx: Transaction,
): GetScriptReturn {
const res: GetScriptReturn = {
script: null,
@ -584,7 +631,6 @@ function getScriptFromInput(
res.isP2SH = true;
res.script = input.redeemScript;
} else {
const unsignedTx = Transaction.fromBuffer(_unsignedTx);
const nonWitnessUtxoTx = Transaction.fromBuffer(input.nonWitnessUtxo);
const prevoutIndex = unsignedTx.ins[inputIndex].index;
res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;

5
types/psbt.d.ts vendored
View file

@ -1,9 +1,12 @@
/// <reference types="node" />
import { Psbt as PsbtBase } from 'bip174';
import { TransactionInput, TransactionOutput } from 'bip174/src/lib/interfaces';
import { Signer, SignerAsync } from './ecpair';
import { Network } from './networks';
import { Transaction } from './transaction';
export declare class Psbt extends PsbtBase {
static fromTransaction<T extends typeof PsbtBase>(this: T, txBuf: Buffer): InstanceType<T>;
static fromBuffer<T extends typeof PsbtBase>(this: T, buffer: Buffer): InstanceType<T>;
private __TX;
private __TX_BUF_CACHE?;
private opts;
@ -18,7 +21,7 @@ export declare class Psbt extends PsbtBase {
inputResults: boolean[];
};
finalizeInput(inputIndex: number): boolean;
signInput(inputIndex: number, keyPair: Signer): Psbt;
signInput(inputIndex: number, keyPair: Signer): this;
signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise<void>;
}
interface PsbtOptsOptional {