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 transaction_1 = require('./transaction');
|
||||||
const varuint = require('varuint-bitcoin');
|
const varuint = require('varuint-bitcoin');
|
||||||
class Psbt extends bip174_1.Psbt {
|
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 = {}) {
|
constructor(opts = {}) {
|
||||||
super();
|
super();
|
||||||
// set defaults
|
// set defaults
|
||||||
|
@ -40,7 +73,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
enumerable,
|
enumerable,
|
||||||
writable,
|
writable,
|
||||||
});
|
});
|
||||||
dpew(this, '__TX', false, false);
|
dpew(this, '__TX', false, true);
|
||||||
dpew(this, '__TX_BUF_CACHE', false, true);
|
dpew(this, '__TX_BUF_CACHE', false, true);
|
||||||
dpew(this, 'opts', false, true);
|
dpew(this, 'opts', false, true);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +145,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
}
|
}
|
||||||
extractTransaction() {
|
extractTransaction() {
|
||||||
if (!this.inputs.every(isFinalized)) throw new Error('Not finalized');
|
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) => {
|
this.inputs.forEach((input, idx) => {
|
||||||
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
|
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
|
||||||
if (input.finalScriptWitness) {
|
if (input.finalScriptWitness) {
|
||||||
|
@ -138,7 +171,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
|
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
|
||||||
inputIndex,
|
inputIndex,
|
||||||
input,
|
input,
|
||||||
this.globalMap.unsignedTx,
|
this.__TX,
|
||||||
);
|
);
|
||||||
if (!script) return false;
|
if (!script) return false;
|
||||||
const scriptType = classifyScript(script);
|
const scriptType = classifyScript(script);
|
||||||
|
@ -166,7 +199,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
this.inputs,
|
this.inputs,
|
||||||
inputIndex,
|
inputIndex,
|
||||||
keyPair.publicKey,
|
keyPair.publicKey,
|
||||||
this.globalMap.unsignedTx,
|
this.__TX,
|
||||||
);
|
);
|
||||||
const partialSig = {
|
const partialSig = {
|
||||||
pubkey: keyPair.publicKey,
|
pubkey: keyPair.publicKey,
|
||||||
|
@ -182,7 +215,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
this.inputs,
|
this.inputs,
|
||||||
inputIndex,
|
inputIndex,
|
||||||
keyPair.publicKey,
|
keyPair.publicKey,
|
||||||
this.globalMap.unsignedTx,
|
this.__TX,
|
||||||
);
|
);
|
||||||
Promise.resolve(keyPair.sign(hash)).then(signature => {
|
Promise.resolve(keyPair.sign(hash)).then(signature => {
|
||||||
const partialSig = {
|
const partialSig = {
|
||||||
|
@ -202,9 +235,13 @@ const DEFAULT_OPTS = {
|
||||||
function isFinalized(input) {
|
function isFinalized(input) {
|
||||||
return !!input.finalScriptSig || !!input.finalScriptWitness;
|
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 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);
|
checkScriptForPubkey(pubkey, script);
|
||||||
return {
|
return {
|
||||||
hash,
|
hash,
|
||||||
|
@ -322,8 +359,7 @@ function checkScriptForPubkey(pubkey, script) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getHashForSig = (inputIndex, input, txBuf) => {
|
const getHashForSig = (inputIndex, input, unsignedTx) => {
|
||||||
const unsignedTx = transaction_1.Transaction.fromBuffer(txBuf);
|
|
||||||
const sighashType =
|
const sighashType =
|
||||||
input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
|
input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
|
||||||
let hash;
|
let hash;
|
||||||
|
@ -442,7 +478,7 @@ const classifyScript = script => {
|
||||||
if (isP2PK(script)) return 'pubkey';
|
if (isP2PK(script)) return 'pubkey';
|
||||||
return 'nonstandard';
|
return 'nonstandard';
|
||||||
};
|
};
|
||||||
function getScriptFromInput(inputIndex, input, _unsignedTx) {
|
function getScriptFromInput(inputIndex, input, unsignedTx) {
|
||||||
const res = {
|
const res = {
|
||||||
script: null,
|
script: null,
|
||||||
isSegwit: false,
|
isSegwit: false,
|
||||||
|
@ -454,7 +490,6 @@ function getScriptFromInput(inputIndex, input, _unsignedTx) {
|
||||||
res.isP2SH = true;
|
res.isP2SH = true;
|
||||||
res.script = input.redeemScript;
|
res.script = input.redeemScript;
|
||||||
} else {
|
} else {
|
||||||
const unsignedTx = transaction_1.Transaction.fromBuffer(_unsignedTx);
|
|
||||||
const nonWitnessUtxoTx = transaction_1.Transaction.fromBuffer(
|
const nonWitnessUtxoTx = transaction_1.Transaction.fromBuffer(
|
||||||
input.nonWitnessUtxo,
|
input.nonWitnessUtxo,
|
||||||
);
|
);
|
||||||
|
|
|
@ -17,6 +17,50 @@ import { Transaction } from './transaction';
|
||||||
const varuint = require('varuint-bitcoin');
|
const varuint = require('varuint-bitcoin');
|
||||||
|
|
||||||
export class Psbt extends PsbtBase {
|
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: Transaction;
|
||||||
private __TX_BUF_CACHE?: Buffer;
|
private __TX_BUF_CACHE?: Buffer;
|
||||||
private opts: PsbtOpts;
|
private opts: PsbtOpts;
|
||||||
|
@ -56,7 +100,7 @@ export class Psbt extends PsbtBase {
|
||||||
enumerable,
|
enumerable,
|
||||||
writable,
|
writable,
|
||||||
});
|
});
|
||||||
dpew(this, '__TX', false, false);
|
dpew(this, '__TX', false, true);
|
||||||
dpew(this, '__TX_BUF_CACHE', false, true);
|
dpew(this, '__TX_BUF_CACHE', false, true);
|
||||||
dpew(this, 'opts', false, true);
|
dpew(this, 'opts', false, true);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +182,7 @@ export class Psbt extends PsbtBase {
|
||||||
|
|
||||||
extractTransaction(): Transaction {
|
extractTransaction(): Transaction {
|
||||||
if (!this.inputs.every(isFinalized)) throw new Error('Not finalized');
|
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) => {
|
this.inputs.forEach((input, idx) => {
|
||||||
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
|
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
|
||||||
if (input.finalScriptWitness) {
|
if (input.finalScriptWitness) {
|
||||||
|
@ -169,7 +213,7 @@ export class Psbt extends PsbtBase {
|
||||||
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
|
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
|
||||||
inputIndex,
|
inputIndex,
|
||||||
input,
|
input,
|
||||||
this.globalMap.unsignedTx!,
|
this.__TX,
|
||||||
);
|
);
|
||||||
if (!script) return false;
|
if (!script) return false;
|
||||||
|
|
||||||
|
@ -195,14 +239,14 @@ export class Psbt extends PsbtBase {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
signInput(inputIndex: number, keyPair: Signer): Psbt {
|
signInput(inputIndex: number, keyPair: Signer): this {
|
||||||
if (!keyPair || !keyPair.publicKey)
|
if (!keyPair || !keyPair.publicKey)
|
||||||
throw new Error('Need Signer to sign input');
|
throw new Error('Need Signer to sign input');
|
||||||
const { hash, sighashType } = getHashAndSighashType(
|
const { hash, sighashType } = getHashAndSighashType(
|
||||||
this.inputs,
|
this.inputs,
|
||||||
inputIndex,
|
inputIndex,
|
||||||
keyPair.publicKey,
|
keyPair.publicKey,
|
||||||
this.globalMap.unsignedTx!,
|
this.__TX,
|
||||||
);
|
);
|
||||||
|
|
||||||
const partialSig = {
|
const partialSig = {
|
||||||
|
@ -222,7 +266,7 @@ export class Psbt extends PsbtBase {
|
||||||
this.inputs,
|
this.inputs,
|
||||||
inputIndex,
|
inputIndex,
|
||||||
keyPair.publicKey,
|
keyPair.publicKey,
|
||||||
this.globalMap.unsignedTx!,
|
this.__TX,
|
||||||
);
|
);
|
||||||
|
|
||||||
Promise.resolve(keyPair.sign(hash)).then(signature => {
|
Promise.resolve(keyPair.sign(hash)).then(signature => {
|
||||||
|
@ -269,13 +313,17 @@ function getHashAndSighashType(
|
||||||
inputs: PsbtInput[],
|
inputs: PsbtInput[],
|
||||||
inputIndex: number,
|
inputIndex: number,
|
||||||
pubkey: Buffer,
|
pubkey: Buffer,
|
||||||
txBuf: Buffer,
|
unsignedTx: Transaction,
|
||||||
): {
|
): {
|
||||||
hash: Buffer;
|
hash: Buffer;
|
||||||
sighashType: number;
|
sighashType: number;
|
||||||
} {
|
} {
|
||||||
const input = checkForInput(inputs, inputIndex);
|
const input = checkForInput(inputs, inputIndex);
|
||||||
const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf);
|
const { hash, sighashType, script } = getHashForSig(
|
||||||
|
inputIndex,
|
||||||
|
input,
|
||||||
|
unsignedTx,
|
||||||
|
);
|
||||||
checkScriptForPubkey(pubkey, script);
|
checkScriptForPubkey(pubkey, script);
|
||||||
return {
|
return {
|
||||||
hash,
|
hash,
|
||||||
|
@ -424,9 +472,8 @@ interface HashForSigData {
|
||||||
const getHashForSig = (
|
const getHashForSig = (
|
||||||
inputIndex: number,
|
inputIndex: number,
|
||||||
input: PsbtInput,
|
input: PsbtInput,
|
||||||
txBuf: Buffer,
|
unsignedTx: Transaction,
|
||||||
): HashForSigData => {
|
): HashForSigData => {
|
||||||
const unsignedTx = Transaction.fromBuffer(txBuf);
|
|
||||||
const sighashType = input.sighashType || Transaction.SIGHASH_ALL;
|
const sighashType = input.sighashType || Transaction.SIGHASH_ALL;
|
||||||
let hash: Buffer;
|
let hash: Buffer;
|
||||||
let script: Buffer;
|
let script: Buffer;
|
||||||
|
@ -571,7 +618,7 @@ interface GetScriptReturn {
|
||||||
function getScriptFromInput(
|
function getScriptFromInput(
|
||||||
inputIndex: number,
|
inputIndex: number,
|
||||||
input: PsbtInput,
|
input: PsbtInput,
|
||||||
_unsignedTx: Buffer,
|
unsignedTx: Transaction,
|
||||||
): GetScriptReturn {
|
): GetScriptReturn {
|
||||||
const res: GetScriptReturn = {
|
const res: GetScriptReturn = {
|
||||||
script: null,
|
script: null,
|
||||||
|
@ -584,7 +631,6 @@ function getScriptFromInput(
|
||||||
res.isP2SH = true;
|
res.isP2SH = true;
|
||||||
res.script = input.redeemScript;
|
res.script = input.redeemScript;
|
||||||
} else {
|
} else {
|
||||||
const unsignedTx = Transaction.fromBuffer(_unsignedTx);
|
|
||||||
const nonWitnessUtxoTx = Transaction.fromBuffer(input.nonWitnessUtxo);
|
const nonWitnessUtxoTx = Transaction.fromBuffer(input.nonWitnessUtxo);
|
||||||
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
||||||
res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
|
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 { Psbt as PsbtBase } from 'bip174';
|
||||||
import { TransactionInput, 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 {
|
||||||
|
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;
|
||||||
private __TX_BUF_CACHE?;
|
private __TX_BUF_CACHE?;
|
||||||
private opts;
|
private opts;
|
||||||
|
@ -18,7 +21,7 @@ export declare class Psbt extends PsbtBase {
|
||||||
inputResults: boolean[];
|
inputResults: boolean[];
|
||||||
};
|
};
|
||||||
finalizeInput(inputIndex: number): boolean;
|
finalizeInput(inputIndex: number): boolean;
|
||||||
signInput(inputIndex: number, keyPair: Signer): Psbt;
|
signInput(inputIndex: number, keyPair: Signer): this;
|
||||||
signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise<void>;
|
signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise<void>;
|
||||||
}
|
}
|
||||||
interface PsbtOptsOptional {
|
interface PsbtOptsOptional {
|
||||||
|
|
Loading…
Reference in a new issue