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": { "bip174": {
"version": "0.0.8", "version": "0.0.10",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.8.tgz", "resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.10.tgz",
"integrity": "sha512-xWPzmlCvLoOWTlXk1wG7+TyOfaN8xX07IieuG4ug5su3igC9s4Lsdq+IEEMo+YHDQ4hPPAX9LYio6aEIAA+Zrg==" "integrity": "sha512-gFtSEMayg7HPKGnIQcEx5CqD/qHWuMlxLJ/+VV4k4Q2mcA0rY040JbNpFuCGVI6rJYv211f0NA7nkU4xkPX4nQ=="
}, },
"bip32": { "bip32": {
"version": "2.0.3", "version": "2.0.3",

2
package.json

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

60
src/psbt.js

@ -1,6 +1,8 @@
'use strict'; 'use strict';
Object.defineProperty(exports, '__esModule', { value: true }); Object.defineProperty(exports, '__esModule', { value: true });
const bip174_1 = require('bip174'); const bip174_1 = require('bip174');
const utils_1 = require('bip174/src/lib/utils');
const classify = require('./classify');
const payments = require('./payments'); const payments = require('./payments');
const bscript = require('./script'); const bscript = require('./script');
const transaction_1 = require('./transaction'); const transaction_1 = require('./transaction');
@ -23,17 +25,67 @@ const checkWitnessScript = scriptCheckerFactory(
payments.p2wsh, payments.p2wsh,
'Witness script', 'Witness script',
); );
const isP2WPKH = script => { const isPayment = (script, payment) => {
try { try {
payments.p2wpkh({ output: script }); payment({ output: script });
return true; return true;
} catch (err) { } catch (err) {
return false; 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 { class Psbt extends bip174_1.Psbt {
constructor() { constructor(network) {
super(); 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) { signInput(inputIndex, keyPair) {
// TODO: Implement BIP174 pre-sign checks: // TODO: Implement BIP174 pre-sign checks:
@ -108,7 +160,7 @@ class Psbt extends bip174_1.Psbt {
} else { } else {
script = input.witnessUtxo.script; script = input.witnessUtxo.script;
} }
if (isP2WPKH(script)) { if (isPayment(script, payments.p2wpkh)) {
// P2WPKH uses the P2PKH template for prevoutScript when signing // P2WPKH uses the P2PKH template for prevoutScript when signing
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output; const signingScript = payments.p2pkh({ hash: script.slice(2) }).output;
hash = unsignedTx.hashForWitnessV0( hash = unsignedTx.hashForWitnessV0(

65
ts_src/psbt.ts

@ -1,5 +1,9 @@
import { Psbt as PsbtBase } from 'bip174'; 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 { Signer } from './ecpair';
import { Network } from './networks';
import * as payments from './payments'; import * as payments from './payments';
import * as bscript from './script'; import * as bscript from './script';
import { Transaction } from './transaction'; import { Transaction } from './transaction';
@ -31,20 +35,73 @@ const checkWitnessScript = scriptCheckerFactory(
'Witness script', 'Witness script',
); );
const isP2WPKH = (script: Buffer): boolean => { const isPayment = (script: Buffer, payment: any): boolean => {
try { try {
payments.p2wpkh({ output: script }); payment({ output: script });
return true; return true;
} catch (err) { } catch (err) {
return false; 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 { export class Psbt extends PsbtBase {
constructor() { constructor(public network?: Network) {
super(); 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 { signInput(inputIndex: number, keyPair: Signer): Psbt {
// TODO: Implement BIP174 pre-sign checks: // TODO: Implement BIP174 pre-sign checks:
// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer // https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer
@ -121,7 +178,7 @@ export class Psbt extends PsbtBase {
} else { } else {
script = input.witnessUtxo.script; script = input.witnessUtxo.script;
} }
if (isP2WPKH(script)) { if (isPayment(script, payments.p2wpkh)) {
// P2WPKH uses the P2PKH template for prevoutScript when signing // P2WPKH uses the P2PKH template for prevoutScript when signing
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output!; const signingScript = payments.p2pkh({ hash: script.slice(2) }).output!;
hash = unsignedTx.hashForWitnessV0( hash = unsignedTx.hashForWitnessV0(

5
types/psbt.d.ts

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

Loading…
Cancel
Save