diff --git a/src/psbt.js b/src/psbt.js index 4c80a31..58a56dd 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -187,14 +187,9 @@ class Psbt extends bip174_1.Psbt { return c.__FEE_RATE; } finalizeAllInputs() { - const inputResults = range(this.inputs.length).map(idx => - this.finalizeInput(idx), - ); - const result = inputResults.every(val => val === true); - return { - result, - inputResults, - }; + utils_1.checkForInput(this.inputs, 0); // making sure we have at least one + range(this.inputs.length).forEach(idx => this.finalizeInput(idx)); + return this; } finalizeInput(inputIndex) { const input = utils_1.checkForInput(this.inputs, inputIndex); @@ -203,9 +198,10 @@ class Psbt extends bip174_1.Psbt { input, this.__CACHE, ); - if (!script) return false; + if (!script) throw new Error(`No script found for input #${inputIndex}`); const scriptType = classifyScript(script); - if (!canFinalize(input, script, scriptType)) return false; + if (!canFinalize(input, script, scriptType)) + throw new Error(`Can not finalize input #${inputIndex}`); const { finalScriptSig, finalScriptWitness } = getFinalScripts( script, scriptType, @@ -218,9 +214,17 @@ class Psbt extends bip174_1.Psbt { this.addFinalScriptSigToInput(inputIndex, finalScriptSig); if (finalScriptWitness) this.addFinalScriptWitnessToInput(inputIndex, finalScriptWitness); - if (!finalScriptSig && !finalScriptWitness) return false; + if (!finalScriptSig && !finalScriptWitness) + throw new Error(`Unknown error finalizing input #${inputIndex}`); this.clearFinalizedInput(inputIndex); - return true; + return this; + } + validateAllSignatures() { + utils_1.checkForInput(this.inputs, 0); // making sure we have at least one + const results = range(this.inputs.length).map(idx => + this.validateSignatures(idx), + ); + return results.reduce((final, res) => res === true && final, true); } validateSignatures(inputIndex, pubkey) { const input = this.inputs[inputIndex]; @@ -261,7 +265,7 @@ class Psbt extends bip174_1.Psbt { // as input information is added, then eventually // optimize this method. const results = []; - for (const [i] of this.inputs.entries()) { + for (const i of range(this.inputs.length)) { try { this.signInput(i, keyPair); results.push(true); diff --git a/test/integration/transactions-psbt.js b/test/integration/transactions-psbt.js index 37348c1..a7398a8 100644 --- a/test/integration/transactions-psbt.js +++ b/test/integration/transactions-psbt.js @@ -225,26 +225,25 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { } = inputData assert.deepStrictEqual({ hash, index, witnessUtxo, redeemScript }, inputData) } + const keyPair = p2sh.keys[0] + const outputData = { + script: p2sh.payment.output, // sending to myself for fun + value: 2e4 + } - const psbt = new bitcoin.Psbt({ network: regtest }) + const tx = new bitcoin.Psbt() .addInput(inputData) - .addOutput({ - address: regtestUtils.RANDOM_ADDRESS, - value: 2e4 - }) - .signInput(0, p2sh.keys[0]) - - assert.strictEqual(psbt.validateSignatures(0), true) - psbt.finalizeAllInputs() - - const tx = psbt.extractTransaction() + .addOutput(outputData) + .sign(keyPair) + .finalizeAllInputs() + .extractTransaction() // build and broadcast to the Bitcoin RegTest network await regtestUtils.broadcast(tx.toHex()) await regtestUtils.verify({ txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, + address: p2sh.payment.address, vout: 0, value: 2e4 }) diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 2e4c826..61ed15e 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -233,31 +233,24 @@ export class Psbt extends PsbtBase { return c.__FEE_RATE!; } - finalizeAllInputs(): { - result: boolean; - inputResults: boolean[]; - } { - const inputResults = range(this.inputs.length).map(idx => - this.finalizeInput(idx), - ); - const result = inputResults.every(val => val === true); - return { - result, - inputResults, - }; + finalizeAllInputs(): this { + checkForInput(this.inputs, 0); // making sure we have at least one + range(this.inputs.length).forEach(idx => this.finalizeInput(idx)); + return this; } - finalizeInput(inputIndex: number): boolean { + finalizeInput(inputIndex: number): this { const input = checkForInput(this.inputs, inputIndex); const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput( inputIndex, input, this.__CACHE, ); - if (!script) return false; + if (!script) throw new Error(`No script found for input #${inputIndex}`); const scriptType = classifyScript(script); - if (!canFinalize(input, script, scriptType)) return false; + if (!canFinalize(input, script, scriptType)) + throw new Error(`Can not finalize input #${inputIndex}`); const { finalScriptSig, finalScriptWitness } = getFinalScripts( script, @@ -272,10 +265,19 @@ export class Psbt extends PsbtBase { this.addFinalScriptSigToInput(inputIndex, finalScriptSig); if (finalScriptWitness) this.addFinalScriptWitnessToInput(inputIndex, finalScriptWitness); - if (!finalScriptSig && !finalScriptWitness) return false; + if (!finalScriptSig && !finalScriptWitness) + throw new Error(`Unknown error finalizing input #${inputIndex}`); this.clearFinalizedInput(inputIndex); - return true; + return this; + } + + validateAllSignatures(): boolean { + checkForInput(this.inputs, 0); // making sure we have at least one + const results = range(this.inputs.length).map(idx => + this.validateSignatures(idx), + ); + return results.reduce((final, res) => res === true && final, true); } validateSignatures(inputIndex: number, pubkey?: Buffer): boolean { @@ -319,7 +321,7 @@ export class Psbt extends PsbtBase { // as input information is added, then eventually // optimize this method. const results: boolean[] = []; - for (const [i] of this.inputs.entries()) { + for (const i of range(this.inputs.length)) { try { this.signInput(i, keyPair); results.push(true); diff --git a/types/psbt.d.ts b/types/psbt.d.ts index 775f3b0..40571fa 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -20,11 +20,9 @@ export declare class Psbt extends PsbtBase { addNonWitnessUtxoToInput(inputIndex: number, nonWitnessUtxo: NonWitnessUtxo): this; extractTransaction(disableFeeCheck?: boolean): Transaction; getFeeRate(): number; - finalizeAllInputs(): { - result: boolean; - inputResults: boolean[]; - }; - finalizeInput(inputIndex: number): boolean; + finalizeAllInputs(): this; + finalizeInput(inputIndex: number): this; + validateAllSignatures(): boolean; validateSignatures(inputIndex: number, pubkey?: Buffer): boolean; sign(keyPair: Signer): this; signAsync(keyPair: SignerAsync): Promise;