PSBT Bugfix for multiple of same pubkey in p2ms
This commit is contained in:
parent
29e319525f
commit
e10324f850
3 changed files with 66 additions and 8 deletions
20
src/psbt.js
20
src/psbt.js
|
@ -568,15 +568,27 @@ function canFinalize(input, script, scriptType) {
|
||||||
return hasSigs(1, input.partialSig);
|
return hasSigs(1, input.partialSig);
|
||||||
case 'multisig':
|
case 'multisig':
|
||||||
const p2ms = payments.p2ms({ output: script });
|
const p2ms = payments.p2ms({ output: script });
|
||||||
return hasSigs(p2ms.m, input.partialSig);
|
return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function hasSigs(neededSigs, partialSig) {
|
function hasSigs(neededSigs, partialSig, pubkeys) {
|
||||||
if (!partialSig) return false;
|
if (!partialSig) return false;
|
||||||
if (partialSig.length > neededSigs) throw new Error('Too many signatures');
|
let sigs;
|
||||||
return partialSig.length === neededSigs;
|
if (pubkeys) {
|
||||||
|
sigs = pubkeys
|
||||||
|
.map(pkey => {
|
||||||
|
const pubkey = ecpair_1.fromPublicKey(pkey, { compressed: true })
|
||||||
|
.publicKey;
|
||||||
|
return partialSig.filter(pSig => pSig.pubkey.equals(pubkey))[0];
|
||||||
|
})
|
||||||
|
.filter(v => !!v);
|
||||||
|
} else {
|
||||||
|
sigs = partialSig;
|
||||||
|
}
|
||||||
|
if (sigs.length > neededSigs) throw new Error('Too many signatures');
|
||||||
|
return sigs.length === neededSigs;
|
||||||
}
|
}
|
||||||
function isFinalized(input) {
|
function isFinalized(input) {
|
||||||
return !!input.finalScriptSig || !!input.finalScriptWitness;
|
return !!input.finalScriptSig || !!input.finalScriptWitness;
|
||||||
|
|
|
@ -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 () => {
|
it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input using HD', async () => {
|
||||||
const hdRoot = bip32.fromSeed(rng(64));
|
const hdRoot = bip32.fromSeed(rng(64));
|
||||||
const masterFingerprint = hdRoot.fingerprint;
|
const masterFingerprint = hdRoot.fingerprint;
|
||||||
|
|
|
@ -747,16 +747,32 @@ function canFinalize(
|
||||||
return hasSigs(1, input.partialSig);
|
return hasSigs(1, input.partialSig);
|
||||||
case 'multisig':
|
case 'multisig':
|
||||||
const p2ms = payments.p2ms({ output: script });
|
const p2ms = payments.p2ms({ output: script });
|
||||||
return hasSigs(p2ms.m!, input.partialSig);
|
return hasSigs(p2ms.m!, input.partialSig, p2ms.pubkeys);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasSigs(neededSigs: number, partialSig?: any[]): boolean {
|
function hasSigs(
|
||||||
|
neededSigs: number,
|
||||||
|
partialSig?: any[],
|
||||||
|
pubkeys?: Buffer[],
|
||||||
|
): boolean {
|
||||||
if (!partialSig) return false;
|
if (!partialSig) return false;
|
||||||
if (partialSig.length > neededSigs) throw new Error('Too many signatures');
|
let sigs: any;
|
||||||
return partialSig.length === neededSigs;
|
if (pubkeys) {
|
||||||
|
sigs = pubkeys
|
||||||
|
.map(pkey => {
|
||||||
|
const pubkey = ecPairFromPublicKey(pkey, { compressed: true })
|
||||||
|
.publicKey;
|
||||||
|
return partialSig.filter(pSig => pSig.pubkey.equals(pubkey))[0];
|
||||||
|
})
|
||||||
|
.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 {
|
function isFinalized(input: PsbtInput): boolean {
|
||||||
|
|
Loading…
Reference in a new issue