Skip to content

Commit 2199a00

Browse files
Merge pull request #7221 from BitGo/BTC-000.fix-logic
test(utxo-lib): add tests for both PSBT and PSBT-lite formats
2 parents ada0cc3 + f098b39 commit 2199a00

File tree

1 file changed

+58
-38
lines changed
  • modules/utxo-lib/test/bitgo/psbt

1 file changed

+58
-38
lines changed

modules/utxo-lib/test/bitgo/psbt/Psbt.ts

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -745,47 +745,67 @@ describe('Update incomplete psbt', function () {
745745
signAllInputs(psbt);
746746
});
747747

748-
const componentsOnEachInputScriptType = {
749-
p2sh: ['nonWitnessUtxo', 'redeemScript', 'bip32Derivation'],
750-
p2shP2wsh: ['witnessUtxo', 'bip32Derivation', 'redeemScript', 'witnessScript'],
751-
p2wsh: ['witnessUtxo', 'witnessScript', 'bip32Derivation'],
752-
p2tr: ['witnessUtxo', 'tapLeafScript', 'tapBip32Derivation'],
753-
p2trMusig2: ['witnessUtxo', 'tapBip32Derivation', 'tapInternalKey', 'tapMerkleRoot', 'unknownKeyVals'],
754-
p2shP2pk: ['redeemScript', 'nonWitnessUtxo'],
755-
};
756-
757-
const p2trComponents = ['tapTree', 'tapInternalKey', 'tapBip32Derivation'];
758-
const componentsOnEachOutputScriptType = {
759-
p2sh: ['bip32Derivation', 'redeemScript'],
760-
p2shP2wsh: ['bip32Derivation', 'witnessScript', 'redeemScript'],
761-
p2wsh: ['bip32Derivation', 'witnessScript'],
762-
p2tr: p2trComponents,
763-
p2trMusig2: p2trComponents,
764-
p2shP2pk: [],
765-
};
766-
scriptTypes.forEach((scriptType, i) => {
767-
componentsOnEachInputScriptType[scriptType].forEach((inputComponent) => {
768-
it(`[${scriptType}] missing ${inputComponent} on input should succeed in fully signing unsigned psbt after update`, function () {
769-
const psbt = removeFromPsbt(psbtHex, network, { input: { index: i, fieldToRemove: inputComponent } });
770-
const unspent = unspents[i];
771-
if (isWalletUnspent(unspent)) {
772-
updateWalletUnspentForPsbt(psbt, i, unspent, rootWalletKeys, signer, cosigner);
773-
} else {
774-
const { redeemScript } = createOutputScriptP2shP2pk(replayProtectionKeyPair.publicKey);
775-
assert.ok(redeemScript);
776-
updateReplayProtectionUnspentToPsbt(psbt, i, unspent, redeemScript);
777-
}
778-
signAllInputs(psbt);
779-
});
780-
});
748+
function runTest(txFormat: 'psbt' | 'psbt-lite') {
749+
describe(`txFormat=${txFormat}`, function () {
750+
const componentsOnEachInputScriptType = {
751+
p2sh: [txFormat === 'psbt' ? 'nonWitnessUtxo' : 'witnessUtxo', 'redeemScript', 'bip32Derivation'],
752+
p2shP2wsh: ['witnessUtxo', 'bip32Derivation', 'redeemScript', 'witnessScript'],
753+
p2wsh: ['witnessUtxo', 'witnessScript', 'bip32Derivation'],
754+
p2tr: ['witnessUtxo', 'tapLeafScript', 'tapBip32Derivation'],
755+
p2trMusig2: ['witnessUtxo', 'tapBip32Derivation', 'tapInternalKey', 'tapMerkleRoot', 'unknownKeyVals'],
756+
p2shP2pk: ['redeemScript', txFormat === 'psbt' ? 'nonWitnessUtxo' : 'witnessUtxo'],
757+
};
781758

782-
componentsOnEachOutputScriptType[scriptType].forEach((outputComponent) => {
783-
it(`[${scriptType}] missing ${outputComponent} on output should produce same hex as fully hydrated after update`, function () {
784-
const psbt = removeFromPsbt(psbtHex, network, { output: { index: i, fieldToRemove: outputComponent } });
785-
updateWalletOutputForPsbt(psbt, rootWalletKeys, i, outputs[i].chain, outputs[i].index);
786-
assert.strictEqual(psbt.toHex(), psbtHex);
759+
const p2trComponents = ['tapTree', 'tapInternalKey', 'tapBip32Derivation'];
760+
const componentsOnEachOutputScriptType = {
761+
p2sh: ['bip32Derivation', 'redeemScript'],
762+
p2shP2wsh: ['bip32Derivation', 'witnessScript', 'redeemScript'],
763+
p2wsh: ['bip32Derivation', 'witnessScript'],
764+
p2tr: p2trComponents,
765+
p2trMusig2: p2trComponents,
766+
p2shP2pk: [],
767+
};
768+
scriptTypes.forEach((scriptType, i) => {
769+
componentsOnEachInputScriptType[scriptType].forEach((inputComponent) => {
770+
it(`[${scriptType}] missing ${inputComponent} on input should succeed in fully signing unsigned psbt after update`, function () {
771+
const psbt = removeFromPsbt(psbtHex, network, {
772+
input: { index: i, fieldToRemove: inputComponent },
773+
});
774+
const unspent = unspents[i];
775+
if (txFormat === 'psbt-lite') {
776+
// remove the prevTx for the unspent
777+
delete (unspent as unknown as { prevTx?: Buffer }).prevTx;
778+
}
779+
if (isWalletUnspent(unspent)) {
780+
updateWalletUnspentForPsbt(psbt, i, unspent, rootWalletKeys, signer, cosigner, {
781+
skipNonWitnessUtxo: txFormat === 'psbt-lite',
782+
});
783+
} else {
784+
const { redeemScript } = createOutputScriptP2shP2pk(replayProtectionKeyPair.publicKey);
785+
assert.ok(redeemScript);
786+
updateReplayProtectionUnspentToPsbt(psbt, i, unspent, redeemScript, {
787+
skipNonWitnessUtxo: txFormat === 'psbt-lite',
788+
});
789+
}
790+
signAllInputs(psbt);
791+
});
792+
});
793+
794+
componentsOnEachOutputScriptType[scriptType].forEach((outputComponent) => {
795+
it(`[${scriptType}] missing ${outputComponent} on output should produce same hex as fully hydrated after update`, function () {
796+
const psbt = removeFromPsbt(psbtHex, network, {
797+
output: { index: i, fieldToRemove: outputComponent },
798+
});
799+
updateWalletOutputForPsbt(psbt, rootWalletKeys, i, outputs[i].chain, outputs[i].index);
800+
assert.strictEqual(psbt.toHex(), psbtHex);
801+
});
802+
});
787803
});
788804
});
805+
}
806+
807+
['psbt', 'psbt-lite'].forEach((txFormat) => {
808+
runTest(txFormat as 'psbt' | 'psbt-lite');
789809
});
790810
});
791811

0 commit comments

Comments
 (0)