Remove unnecessary extra Transaction Buffer parsing
This commit is contained in:
parent
b98761a283
commit
5b5daf84dd
3 changed files with 108 additions and 24 deletions
57
src/psbt.js
57
src/psbt.js
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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
5
types/psbt.d.ts
vendored
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue