Skip to content

Commit e67a4f3

Browse files
davidkaplanbitgollm-git
andcommitted
fix(utxo-lib): add tests for both PSBT and PSBT-lite formats
Refactor tests to run for both standard PSBT and PSBT-lite formats, ensuring our implementation works with both input formats. The changes allow testing with both witnessUtxo and nonWitnessUtxo depending on the format. Issue: BTC-000 Co-authored-by: llm-git <llm-git@ttll.de>
1 parent dc4871f commit e67a4f3

1 file changed

Lines changed: 59 additions & 38 deletions

File tree

  • modules/utxo-lib/test/bitgo/psbt

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

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
WalletUnspent,
3737
getDefaultSigHash,
3838
isPsbtLite,
39+
UnspentWithPrevTx,
3940
} from '../../../src/bitgo';
4041
import {
4142
createOutputScript2of3,
@@ -745,47 +746,67 @@ describe('Update incomplete psbt', function () {
745746
signAllInputs(psbt);
746747
});
747748

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-
});
749+
function runTest(txFormat: 'psbt' | 'psbt-lite') {
750+
describe(`txFormat=${txFormat}`, function () {
751+
const componentsOnEachInputScriptType = {
752+
p2sh: [txFormat === 'psbt' ? 'nonWitnessUtxo' : 'witnessUtxo', 'redeemScript', 'bip32Derivation'],
753+
p2shP2wsh: ['witnessUtxo', 'bip32Derivation', 'redeemScript', 'witnessScript'],
754+
p2wsh: ['witnessUtxo', 'witnessScript', 'bip32Derivation'],
755+
p2tr: ['witnessUtxo', 'tapLeafScript', 'tapBip32Derivation'],
756+
p2trMusig2: ['witnessUtxo', 'tapBip32Derivation', 'tapInternalKey', 'tapMerkleRoot', 'unknownKeyVals'],
757+
p2shP2pk: ['redeemScript', txFormat === 'psbt' ? 'nonWitnessUtxo' : 'witnessUtxo'],
758+
};
781759

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

0 commit comments

Comments
 (0)