Browse Source

Add async signing method

psbt
junderw 6 years ago
parent
commit
77dde89acc
No known key found for this signature in database GPG Key ID: B256185D3A971908
  1. 94
      src/psbt.js
  2. 117
      ts_src/psbt.ts
  3. 2
      tsconfig.json
  4. 3
      types/psbt.d.ts

94
src/psbt.js

@ -56,24 +56,14 @@ class Psbt extends bip174_1.Psbt {
if (!script) return false; if (!script) return false;
const scriptType = classifyScript(script); const scriptType = classifyScript(script);
if (!canFinalize(input, script, scriptType)) return false; if (!canFinalize(input, script, scriptType)) return false;
let finalScriptSig; const { finalScriptSig, finalScriptWitness } = getFinalScripts(
let finalScriptWitness; script,
// Wow, the payments API is very handy scriptType,
const payment = getPayment(script, scriptType, input.partialSig); input.partialSig,
const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment }); isSegwit,
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); isP2SH,
if (isSegwit) { isP2WSH,
if (p2wsh) { );
finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness);
} else {
finalScriptWitness = witnessStackToScriptWitness(payment.witness);
}
if (p2sh) {
finalScriptSig = bscript.compile([p2sh.redeem.output]);
}
} else {
finalScriptSig = payment.input;
}
if (finalScriptSig) if (finalScriptSig)
this.addFinalScriptSigToInput(inputIndex, finalScriptSig); this.addFinalScriptSigToInput(inputIndex, finalScriptSig);
if (finalScriptWitness) if (finalScriptWitness)
@ -83,22 +73,38 @@ class Psbt extends bip174_1.Psbt {
return true; return true;
} }
signInput(inputIndex, keyPair) { signInput(inputIndex, keyPair) {
const input = utils_1.checkForInput(this.inputs, inputIndex);
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, script } = getHashForSig( const { hash, sighashType } = getHashAndSighashType(
this.inputs,
inputIndex, inputIndex,
input, keyPair.publicKey,
this.globalMap.unsignedTx, this.globalMap.unsignedTx,
); );
const pubkey = keyPair.publicKey;
checkScriptForPubkey(pubkey, script);
const partialSig = { const partialSig = {
pubkey, pubkey: keyPair.publicKey,
signature: bscript.signature.encode(keyPair.sign(hash), sighashType), signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
}; };
return this.addPartialSigToInput(inputIndex, partialSig); return this.addPartialSigToInput(inputIndex, partialSig);
} }
async signInputAsync(inputIndex, keyPair) {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
const { hash, sighashType } = getHashAndSighashType(
this.inputs,
inputIndex,
keyPair.publicKey,
this.globalMap.unsignedTx,
);
const partialSig = {
pubkey: keyPair.publicKey,
signature: bscript.signature.encode(
await keyPair.sign(hash),
sighashType,
),
};
this.addPartialSigToInput(inputIndex, partialSig);
}
} }
exports.Psbt = Psbt; exports.Psbt = Psbt;
// //
@ -113,6 +119,46 @@ exports.Psbt = Psbt;
function isFinalized(input) { function isFinalized(input) {
return !!input.finalScriptSig || !!input.finalScriptWitness; return !!input.finalScriptSig || !!input.finalScriptWitness;
} }
function getHashAndSighashType(inputs, inputIndex, pubkey, txBuf) {
const input = utils_1.checkForInput(inputs, inputIndex);
const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf);
checkScriptForPubkey(pubkey, script);
return {
hash,
sighashType,
};
}
function getFinalScripts(
script,
scriptType,
partialSig,
isSegwit,
isP2SH,
isP2WSH,
) {
let finalScriptSig;
let finalScriptWitness;
// Wow, the payments API is very handy
const payment = getPayment(script, scriptType, partialSig);
const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
if (isSegwit) {
if (p2wsh) {
finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness);
} else {
finalScriptWitness = witnessStackToScriptWitness(payment.witness);
}
if (p2sh) {
finalScriptSig = bscript.compile([p2sh.redeem.output]);
}
} else {
finalScriptSig = payment.input;
}
return {
finalScriptSig,
finalScriptWitness,
};
}
function getPayment(script, scriptType, partialSig) { function getPayment(script, scriptType, partialSig) {
let payment; let payment;
switch (scriptType) { switch (scriptType) {

117
ts_src/psbt.ts

@ -2,7 +2,7 @@ import { Psbt as PsbtBase } from 'bip174';
import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces'; import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces';
import { checkForInput } from 'bip174/src/lib/utils'; import { checkForInput } from 'bip174/src/lib/utils';
import { hash160 } from './crypto'; import { hash160 } from './crypto';
import { Signer } from './ecpair'; import { Signer, SignerAsync } from './ecpair';
import { Network } from './networks'; import { Network } from './networks';
import * as payments from './payments'; import * as payments from './payments';
import * as bscript from './script'; import * as bscript from './script';
@ -65,30 +65,14 @@ export class Psbt extends PsbtBase {
const scriptType = classifyScript(script); const scriptType = classifyScript(script);
if (!canFinalize(input, script, scriptType)) return false; if (!canFinalize(input, script, scriptType)) return false;
let finalScriptSig: Buffer | undefined; const { finalScriptSig, finalScriptWitness } = getFinalScripts(
let finalScriptWitness: Buffer | undefined;
// Wow, the payments API is very handy
const payment: payments.Payment = getPayment(
script, script,
scriptType, scriptType,
input.partialSig!, input.partialSig!,
isSegwit,
isP2SH,
isP2WSH,
); );
const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
if (isSegwit) {
if (p2wsh) {
finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness!);
} else {
finalScriptWitness = witnessStackToScriptWitness(payment.witness!);
}
if (p2sh) {
finalScriptSig = bscript.compile([p2sh.redeem!.output!]);
}
} else {
finalScriptSig = payment.input;
}
if (finalScriptSig) if (finalScriptSig)
this.addFinalScriptSigToInput(inputIndex, finalScriptSig); this.addFinalScriptSigToInput(inputIndex, finalScriptSig);
@ -101,26 +85,46 @@ export class Psbt extends PsbtBase {
} }
signInput(inputIndex: number, keyPair: Signer): Psbt { signInput(inputIndex: number, keyPair: Signer): Psbt {
const input = checkForInput(this.inputs, inputIndex);
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, script } = getHashForSig( const { hash, sighashType } = getHashAndSighashType(
this.inputs,
inputIndex, inputIndex,
input, keyPair.publicKey,
this.globalMap.unsignedTx!, this.globalMap.unsignedTx!,
); );
const pubkey = keyPair.publicKey;
checkScriptForPubkey(pubkey, script);
const partialSig = { const partialSig = {
pubkey, pubkey: keyPair.publicKey,
signature: bscript.signature.encode(keyPair.sign(hash), sighashType), signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
}; };
return this.addPartialSigToInput(inputIndex, partialSig); return this.addPartialSigToInput(inputIndex, partialSig);
} }
async signInputAsync(
inputIndex: number,
keyPair: SignerAsync,
): Promise<void> {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
const { hash, sighashType } = getHashAndSighashType(
this.inputs,
inputIndex,
keyPair.publicKey,
this.globalMap.unsignedTx!,
);
const partialSig = {
pubkey: keyPair.publicKey,
signature: bscript.signature.encode(
await keyPair.sign(hash),
sighashType,
),
};
this.addPartialSigToInput(inputIndex, partialSig);
}
} }
// //
@ -137,6 +141,61 @@ function isFinalized(input: PsbtInput): boolean {
return !!input.finalScriptSig || !!input.finalScriptWitness; return !!input.finalScriptSig || !!input.finalScriptWitness;
} }
function getHashAndSighashType(
inputs: PsbtInput[],
inputIndex: number,
pubkey: Buffer,
txBuf: Buffer,
): {
hash: Buffer;
sighashType: number;
} {
const input = checkForInput(inputs, inputIndex);
const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf);
checkScriptForPubkey(pubkey, script);
return {
hash,
sighashType,
};
}
function getFinalScripts(
script: Buffer,
scriptType: string,
partialSig: PartialSig[],
isSegwit: boolean,
isP2SH: boolean,
isP2WSH: boolean,
): {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | undefined;
} {
let finalScriptSig: Buffer | undefined;
let finalScriptWitness: Buffer | undefined;
// Wow, the payments API is very handy
const payment: payments.Payment = getPayment(script, scriptType, partialSig);
const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
if (isSegwit) {
if (p2wsh) {
finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness!);
} else {
finalScriptWitness = witnessStackToScriptWitness(payment.witness!);
}
if (p2sh) {
finalScriptSig = bscript.compile([p2sh.redeem!.output!]);
}
} else {
finalScriptSig = payment.input;
}
return {
finalScriptSig,
finalScriptWitness,
};
}
function getPayment( function getPayment(
script: Buffer, script: Buffer,
scriptType: string, scriptType: string,

2
tsconfig.json

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2015", "target": "ES2017",
"module": "commonjs", "module": "commonjs",
"outDir": "./src", "outDir": "./src",
"declaration": true, "declaration": true,

3
types/psbt.d.ts

@ -1,5 +1,5 @@
import { Psbt as PsbtBase } from 'bip174'; import { Psbt as PsbtBase } from 'bip174';
import { Signer } 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 {
@ -12,4 +12,5 @@ export declare class Psbt extends PsbtBase {
}; };
finalizeInput(inputIndex: number): boolean; finalizeInput(inputIndex: number): boolean;
signInput(inputIndex: number, keyPair: Signer): Psbt; signInput(inputIndex: number, keyPair: Signer): Psbt;
signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise<void>;
} }

Loading…
Cancel
Save