Merge pull request #1519 from bitcoinjs/doubleMSSamekey

PSBT Bugfix for multiple of same pubkey in p2ms
This commit is contained in:
d-yokoi 2020-01-02 00:57:47 +09:00 committed by GitHub
commit 879d49033c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 8 deletions

View file

@ -590,15 +590,27 @@ function canFinalize(input, script, scriptType) {
return hasSigs(1, input.partialSig);
case 'multisig':
const p2ms = payments.p2ms({ output: script });
return hasSigs(p2ms.m, input.partialSig);
return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys);
default:
return false;
}
}
function hasSigs(neededSigs, partialSig) {
function hasSigs(neededSigs, partialSig, pubkeys) {
if (!partialSig) return false;
if (partialSig.length > neededSigs) throw new Error('Too many signatures');
return partialSig.length === neededSigs;
let sigs;
if (pubkeys) {
sigs = pubkeys
.map(pkey => {
const pubkey = ecpair_1.fromPublicKey(pkey, { compressed: true })
.publicKey;
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
})
.filter(v => !!v);
} else {
sigs = partialSig;
}
if (sigs.length > neededSigs) throw new Error('Too many signatures');
return sigs.length === neededSigs;
}
function isFinalized(input) {
return !!input.finalScriptSig || !!input.finalScriptWitness;

View file

@ -530,6 +530,36 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
},
);
it(
'can create (and broadcast via 3PBP) a Transaction, w/ a ' +
'P2SH(P2MS(2 of 2)) input with nonWitnessUtxo',
async () => {
const myKey = bitcoin.ECPair.makeRandom({ network: regtest });
const myKeys = [
myKey,
bitcoin.ECPair.fromPrivateKey(myKey.privateKey!, { network: regtest }),
];
const p2sh = createPayment('p2sh-p2ms(2 of 2)', myKeys);
const inputData = await getInputData(5e4, p2sh.payment, false, 'p2sh');
const psbt = new bitcoin.Psbt({ network: regtest })
.addInput(inputData)
.addOutput({
address: regtestUtils.RANDOM_ADDRESS,
value: 2e4,
})
.signInput(0, p2sh.keys[0]);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction();
await regtestUtils.broadcast(tx.toHex());
await regtestUtils.verify({
txId: tx.getId(),
address: regtestUtils.RANDOM_ADDRESS,
vout: 0,
value: 2e4,
});
},
);
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input using HD', async () => {
const hdRoot = bip32.fromSeed(rng(64));
const masterFingerprint = hdRoot.fingerprint;

View file

@ -770,16 +770,32 @@ function canFinalize(
return hasSigs(1, input.partialSig);
case 'multisig':
const p2ms = payments.p2ms({ output: script });
return hasSigs(p2ms.m!, input.partialSig);
return hasSigs(p2ms.m!, input.partialSig, p2ms.pubkeys);
default:
return false;
}
}
function hasSigs(neededSigs: number, partialSig?: any[]): boolean {
function hasSigs(
neededSigs: number,
partialSig?: any[],
pubkeys?: Buffer[],
): boolean {
if (!partialSig) return false;
if (partialSig.length > neededSigs) throw new Error('Too many signatures');
return partialSig.length === neededSigs;
let sigs: any;
if (pubkeys) {
sigs = pubkeys
.map(pkey => {
const pubkey = ecPairFromPublicKey(pkey, { compressed: true })
.publicKey;
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
})
.filter(v => !!v);
} else {
sigs = partialSig;
}
if (sigs.length > neededSigs) throw new Error('Too many signatures');
return sigs.length === neededSigs;
}
function isFinalized(input: PsbtInput): boolean {