Browse Source

Start towards finalizing inputs

psbt
junderw 6 years ago
parent
commit
f72c915ff1
No known key found for this signature in database GPG Key ID: B256185D3A971908
  1. 6
      package-lock.json
  2. 2
      package.json
  3. 60
      src/psbt.js
  4. 65
      ts_src/psbt.ts
  5. 5
      types/psbt.d.ts

6
package-lock.json

@ -200,9 +200,9 @@
}
},
"bip174": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.8.tgz",
"integrity": "sha512-xWPzmlCvLoOWTlXk1wG7+TyOfaN8xX07IieuG4ug5su3igC9s4Lsdq+IEEMo+YHDQ4hPPAX9LYio6aEIAA+Zrg=="
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.10.tgz",
"integrity": "sha512-gFtSEMayg7HPKGnIQcEx5CqD/qHWuMlxLJ/+VV4k4Q2mcA0rY040JbNpFuCGVI6rJYv211f0NA7nkU4xkPX4nQ=="
},
"bip32": {
"version": "2.0.3",

2
package.json

@ -47,7 +47,7 @@
"dependencies": {
"@types/node": "10.12.18",
"bech32": "^1.1.2",
"bip174": "0.0.8",
"bip174": "0.0.10",
"bip32": "^2.0.3",
"bip66": "^1.1.0",
"bitcoin-ops": "^1.4.0",

60
src/psbt.js

@ -1,6 +1,8 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const bip174_1 = require('bip174');
const utils_1 = require('bip174/src/lib/utils');
const classify = require('./classify');
const payments = require('./payments');
const bscript = require('./script');
const transaction_1 = require('./transaction');
@ -23,17 +25,67 @@ const checkWitnessScript = scriptCheckerFactory(
payments.p2wsh,
'Witness script',
);
const isP2WPKH = script => {
const isPayment = (script, payment) => {
try {
payments.p2wpkh({ output: script });
payment({ output: script });
return true;
} catch (err) {
return false;
}
};
function getScriptFromInput(inputIndex, input, _unsignedTx) {
let script;
if (input.nonWitnessUtxo) {
if (input.redeemScript) {
script = input.redeemScript;
} else {
const unsignedTx = transaction_1.Transaction.fromBuffer(_unsignedTx);
const nonWitnessUtxoTx = transaction_1.Transaction.fromBuffer(
input.nonWitnessUtxo,
);
const prevoutIndex = unsignedTx.ins[inputIndex].index;
script = nonWitnessUtxoTx.outs[prevoutIndex].script;
}
} else if (input.witnessUtxo) {
if (input.witnessScript) {
script = input.witnessScript;
} else if (input.redeemScript) {
script = payments.p2pkh({ hash: input.redeemScript.slice(2) }).output;
} else {
script = payments.p2pkh({ hash: input.witnessUtxo.script.slice(2) })
.output;
}
} else {
return;
}
return script;
}
class Psbt extends bip174_1.Psbt {
constructor() {
constructor(network) {
super();
this.network = network;
}
canFinalize(inputIndex) {
const input = utils_1.checkForInput(this.inputs, inputIndex);
const script = getScriptFromInput(
inputIndex,
input,
this.globalMap.unsignedTx,
);
if (!script) return false;
const scriptType = classify.output(script);
switch (scriptType) {
case 'pubkey':
return false;
case 'pubkeyhash':
return false;
case 'multisig':
return false;
case 'witnesspubkeyhash':
return false;
default:
return false;
}
}
signInput(inputIndex, keyPair) {
// TODO: Implement BIP174 pre-sign checks:
@ -108,7 +160,7 @@ class Psbt extends bip174_1.Psbt {
} else {
script = input.witnessUtxo.script;
}
if (isP2WPKH(script)) {
if (isPayment(script, payments.p2wpkh)) {
// P2WPKH uses the P2PKH template for prevoutScript when signing
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output;
hash = unsignedTx.hashForWitnessV0(

65
ts_src/psbt.ts

@ -1,5 +1,9 @@
import { Psbt as PsbtBase } from 'bip174';
import { PsbtInput } from 'bip174/src/lib/interfaces';
import { checkForInput } from 'bip174/src/lib/utils';
import * as classify from './classify';
import { Signer } from './ecpair';
import { Network } from './networks';
import * as payments from './payments';
import * as bscript from './script';
import { Transaction } from './transaction';
@ -31,20 +35,73 @@ const checkWitnessScript = scriptCheckerFactory(
'Witness script',
);
const isP2WPKH = (script: Buffer): boolean => {
const isPayment = (script: Buffer, payment: any): boolean => {
try {
payments.p2wpkh({ output: script });
payment({ output: script });
return true;
} catch (err) {
return false;
}
};
function getScriptFromInput(
inputIndex: number,
input: PsbtInput,
_unsignedTx: Buffer,
): Buffer | undefined {
let script: Buffer;
if (input.nonWitnessUtxo) {
if (input.redeemScript) {
script = input.redeemScript;
} else {
const unsignedTx = Transaction.fromBuffer(_unsignedTx);
const nonWitnessUtxoTx = Transaction.fromBuffer(input.nonWitnessUtxo);
const prevoutIndex = unsignedTx.ins[inputIndex].index;
script = nonWitnessUtxoTx.outs[prevoutIndex].script;
}
} else if (input.witnessUtxo) {
if (input.witnessScript) {
script = input.witnessScript;
} else if (input.redeemScript) {
script = payments.p2pkh({ hash: input.redeemScript.slice(2) }).output!;
} else {
script = payments.p2pkh({ hash: input.witnessUtxo.script.slice(2) })
.output!;
}
} else {
return;
}
return script;
}
export class Psbt extends PsbtBase {
constructor() {
constructor(public network?: Network) {
super();
}
canFinalize(inputIndex: number): boolean {
const input = checkForInput(this.inputs, inputIndex);
const script = getScriptFromInput(
inputIndex,
input,
this.globalMap.unsignedTx!,
);
if (!script) return false;
const scriptType = classify.output(script);
switch (scriptType) {
case 'pubkey':
return false;
case 'pubkeyhash':
return false;
case 'multisig':
return false;
case 'witnesspubkeyhash':
return false;
default:
return false;
}
}
signInput(inputIndex: number, keyPair: Signer): Psbt {
// TODO: Implement BIP174 pre-sign checks:
// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer
@ -121,7 +178,7 @@ export class Psbt extends PsbtBase {
} else {
script = input.witnessUtxo.script;
}
if (isP2WPKH(script)) {
if (isPayment(script, payments.p2wpkh)) {
// P2WPKH uses the P2PKH template for prevoutScript when signing
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output!;
hash = unsignedTx.hashForWitnessV0(

5
types/psbt.d.ts

@ -1,6 +1,9 @@
import { Psbt as PsbtBase } from 'bip174';
import { Signer } from './ecpair';
import { Network } from './networks';
export declare class Psbt extends PsbtBase {
constructor();
network?: Network | undefined;
constructor(network?: Network | undefined);
canFinalize(inputIndex: number): boolean;
signInput(inputIndex: number, keyPair: Signer): Psbt;
}

Loading…
Cancel
Save