Skip to content

Commit 879d490

Browse files
authored
Merge pull request #1519 from bitcoinjs/doubleMSSamekey
PSBT Bugfix for multiple of same pubkey in p2ms
2 parents 3f6f5ef + 85e4512 commit 879d490

File tree

3 files changed

+66
-8
lines changed

3 files changed

+66
-8
lines changed

src/psbt.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -590,15 +590,27 @@ function canFinalize(input, script, scriptType) {
590590
return hasSigs(1, input.partialSig);
591591
case 'multisig':
592592
const p2ms = payments.p2ms({ output: script });
593-
return hasSigs(p2ms.m, input.partialSig);
593+
return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys);
594594
default:
595595
return false;
596596
}
597597
}
598-
function hasSigs(neededSigs, partialSig) {
598+
function hasSigs(neededSigs, partialSig, pubkeys) {
599599
if (!partialSig) return false;
600-
if (partialSig.length > neededSigs) throw new Error('Too many signatures');
601-
return partialSig.length === neededSigs;
600+
let sigs;
601+
if (pubkeys) {
602+
sigs = pubkeys
603+
.map(pkey => {
604+
const pubkey = ecpair_1.fromPublicKey(pkey, { compressed: true })
605+
.publicKey;
606+
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
607+
})
608+
.filter(v => !!v);
609+
} else {
610+
sigs = partialSig;
611+
}
612+
if (sigs.length > neededSigs) throw new Error('Too many signatures');
613+
return sigs.length === neededSigs;
602614
}
603615
function isFinalized(input) {
604616
return !!input.finalScriptSig || !!input.finalScriptWitness;

test/integration/transactions.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,36 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
530530
},
531531
);
532532

533+
it(
534+
'can create (and broadcast via 3PBP) a Transaction, w/ a ' +
535+
'P2SH(P2MS(2 of 2)) input with nonWitnessUtxo',
536+
async () => {
537+
const myKey = bitcoin.ECPair.makeRandom({ network: regtest });
538+
const myKeys = [
539+
myKey,
540+
bitcoin.ECPair.fromPrivateKey(myKey.privateKey!, { network: regtest }),
541+
];
542+
const p2sh = createPayment('p2sh-p2ms(2 of 2)', myKeys);
543+
const inputData = await getInputData(5e4, p2sh.payment, false, 'p2sh');
544+
const psbt = new bitcoin.Psbt({ network: regtest })
545+
.addInput(inputData)
546+
.addOutput({
547+
address: regtestUtils.RANDOM_ADDRESS,
548+
value: 2e4,
549+
})
550+
.signInput(0, p2sh.keys[0]);
551+
psbt.finalizeAllInputs();
552+
const tx = psbt.extractTransaction();
553+
await regtestUtils.broadcast(tx.toHex());
554+
await regtestUtils.verify({
555+
txId: tx.getId(),
556+
address: regtestUtils.RANDOM_ADDRESS,
557+
vout: 0,
558+
value: 2e4,
559+
});
560+
},
561+
);
562+
533563
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input using HD', async () => {
534564
const hdRoot = bip32.fromSeed(rng(64));
535565
const masterFingerprint = hdRoot.fingerprint;

ts_src/psbt.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -770,16 +770,32 @@ function canFinalize(
770770
return hasSigs(1, input.partialSig);
771771
case 'multisig':
772772
const p2ms = payments.p2ms({ output: script });
773-
return hasSigs(p2ms.m!, input.partialSig);
773+
return hasSigs(p2ms.m!, input.partialSig, p2ms.pubkeys);
774774
default:
775775
return false;
776776
}
777777
}
778778

779-
function hasSigs(neededSigs: number, partialSig?: any[]): boolean {
779+
function hasSigs(
780+
neededSigs: number,
781+
partialSig?: any[],
782+
pubkeys?: Buffer[],
783+
): boolean {
780784
if (!partialSig) return false;
781-
if (partialSig.length > neededSigs) throw new Error('Too many signatures');
782-
return partialSig.length === neededSigs;
785+
let sigs: any;
786+
if (pubkeys) {
787+
sigs = pubkeys
788+
.map(pkey => {
789+
const pubkey = ecPairFromPublicKey(pkey, { compressed: true })
790+
.publicKey;
791+
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
792+
})
793+
.filter(v => !!v);
794+
} else {
795+
sigs = partialSig;
796+
}
797+
if (sigs.length > neededSigs) throw new Error('Too many signatures');
798+
return sigs.length === neededSigs;
783799
}
784800

785801
function isFinalized(input: PsbtInput): boolean {

0 commit comments

Comments
 (0)