Skip to content

Commit 6a46f4b

Browse files
OttoAllmendingerllm-git
andcommitted
test(wasm-utxo): simplify fromHalfSignedLegacy test dependencies
Replace utxolib network objects with coin-based utilities throughout tests for `fromHalfSignedLegacyTransaction`. Update helper functions to accept `CoinName` instead of `Network`, and use new coin utilities for mainnet checks and script type validation. - Replace `isSupportedNetwork` with `isSupportedCoin` using `CoinName` - Update `createHalfSignedP2msPsbt` to use coin-based utilities - Use `supportsScriptType` instead of network-based validation - Replace network list iteration with `coinNames` filtering - Remove `getCoinNameForNetwork` dependency - Clarify test descriptions for transaction instance handling Co-authored-by: llm-git <llm-git@ttll.de>
1 parent 202e04e commit 6a46f4b

1 file changed

Lines changed: 54 additions & 57 deletions

File tree

packages/wasm-utxo/test/fixedScript/fromHalfSignedLegacyTransaction.ts

Lines changed: 54 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,40 @@
1111
*/
1212
import { describe, it } from "mocha";
1313
import * as assert from "assert";
14-
import * as utxolib from "@bitgo/utxo-lib";
1514
import { BitGoPsbt, type HydrationUnspent } from "../../js/fixedScriptWallet/BitGoPsbt.js";
1615
import { ZcashBitGoPsbt } from "../../js/fixedScriptWallet/ZcashBitGoPsbt.js";
16+
import { supportsScriptType } from "../../js/fixedScriptWallet/index.js";
1717
import { ChainCode } from "../../js/fixedScriptWallet/chains.js";
1818
import { ECPair } from "../../js/ecpair.js";
19-
import { Transaction } from "../../js/transaction.js";
19+
import { Transaction, ZcashTransaction } from "../../js/transaction.js";
20+
import { coinNames, type CoinName, isMainnet } from "../../js/coinName.js";
2021
import { getDefaultWalletKeys, getKeyTriple } from "../../js/testutils/keys.js";
21-
import { getCoinNameForNetwork } from "../networks.js";
2222

2323
const ZCASH_NU5_HEIGHT = 1687105;
2424

2525
const p2msScriptTypes = ["p2sh", "p2shP2wsh", "p2wsh"] as const;
2626

27-
function isSupportedNetwork(n: utxolib.Network): boolean {
28-
return utxolib.isMainnet(n) && n !== utxolib.networks.bitcoinsv && n !== utxolib.networks.ecash;
27+
// Coins excluded from round-trip tests (use special handling or not supported)
28+
const EXCLUDED_COINS: CoinName[] = ["bsv", "bcha", "zec"];
29+
30+
function isSupportedCoin(coin: CoinName): boolean {
31+
return isMainnet(coin) && !EXCLUDED_COINS.includes(coin);
2932
}
3033

3134
function createHalfSignedP2msPsbt(
32-
network: utxolib.Network,
35+
coinName: CoinName,
3336
valueOverride?: bigint,
3437
): { psbt: BitGoPsbt; unspents: HydrationUnspent[] } {
35-
const coinName = getCoinNameForNetwork(network);
3638
const rootWalletKeys = getDefaultWalletKeys();
3739
const [userXprv] = getKeyTriple("default");
3840

3941
const supportedTypes = p2msScriptTypes.filter((scriptType) =>
40-
utxolib.bitgo.outputScripts.isSupportedScriptType(network, scriptType),
42+
supportsScriptType(coinName, scriptType),
4143
);
4244

43-
const isZcash = utxolib.getMainnet(network) === utxolib.networks.zcash;
45+
const isZcash = coinName === "zec" || coinName === "tzec";
4446
const psbt = isZcash
45-
? ZcashBitGoPsbt.createEmpty(coinName as "zec" | "tzec", rootWalletKeys, {
47+
? ZcashBitGoPsbt.createEmpty(coinName, rootWalletKeys, {
4648
version: 4,
4749
lockTime: 0,
4850
blockHeight: ZCASH_NU5_HEIGHT,
@@ -79,11 +81,12 @@ describe("BitGoPsbt.fromHalfSignedLegacyTransaction", function () {
7981
// because BigInt::from(value_js).as_f64() calls JsValue::as_f64(), which
8082
// returns None for JS BigInt (it only works for JS Number).
8183
const rootWalletKeys = getDefaultWalletKeys();
82-
const { psbt, unspents } = createHalfSignedP2msPsbt(utxolib.networks.bitcoin);
84+
const { psbt, unspents } = createHalfSignedP2msPsbt("btc");
8385
const txBytes = psbt.getHalfSignedLegacyFormat();
86+
const tx = Transaction.fromBytes(txBytes, "btc");
8487

8588
assert.doesNotThrow(() => {
86-
BitGoPsbt.fromHalfSignedLegacyTransaction(txBytes, "btc", rootWalletKeys, unspents);
89+
BitGoPsbt.fromHalfSignedLegacyTransaction(tx, "btc", rootWalletKeys, unspents);
8790
}, "fromHalfSignedLegacyTransaction must not throw for valid JS BigInt values");
8891
});
8992

@@ -93,33 +96,29 @@ describe("BitGoPsbt.fromHalfSignedLegacyTransaction", function () {
9396
const rootWalletKeys = getDefaultWalletKeys();
9497
// 21 million BTC in satoshis — the maximum possible UTXO value
9598
const maxSats = 21_000_000n * 100_000_000n;
96-
const { psbt, unspents } = createHalfSignedP2msPsbt(utxolib.networks.bitcoin, maxSats);
99+
const { psbt, unspents } = createHalfSignedP2msPsbt("btc", maxSats);
97100
const txBytes = psbt.getHalfSignedLegacyFormat();
101+
const tx = Transaction.fromBytes(txBytes, "btc");
98102

99103
assert.doesNotThrow(() => {
100-
BitGoPsbt.fromHalfSignedLegacyTransaction(txBytes, "btc", rootWalletKeys, unspents);
104+
BitGoPsbt.fromHalfSignedLegacyTransaction(tx, "btc", rootWalletKeys, unspents);
101105
}, "fromHalfSignedLegacyTransaction must handle large satoshi values");
102106
});
103107
});
104108

105109
describe("Round-trip: getHalfSignedLegacyFormat → fromHalfSignedLegacyTransaction", function () {
106-
// Zcash uses a non-standard transaction format (version 4 overwintered) that
107-
// fromHalfSignedLegacyTransaction does not support; skip it here.
108-
const roundTripNetworks = utxolib
109-
.getNetworkList()
110-
.filter(isSupportedNetwork)
111-
.filter((n) => utxolib.getMainnet(n) !== utxolib.networks.zcash);
112-
113-
for (const network of roundTripNetworks) {
114-
const networkName = utxolib.getNetworkName(network);
115-
it(`${networkName}: reconstructed PSBT serializes without error`, function () {
110+
// Supported coins for round-trip: all mainnet UTXO coins except special formats
111+
const roundTripCoins = coinNames.filter(isSupportedCoin);
112+
113+
for (const coinName of roundTripCoins) {
114+
it(`${coinName}: reconstructed PSBT serializes without error`, function () {
116115
const rootWalletKeys = getDefaultWalletKeys();
117-
const coinName = getCoinNameForNetwork(network);
118-
const { psbt, unspents } = createHalfSignedP2msPsbt(network);
116+
const { psbt, unspents } = createHalfSignedP2msPsbt(coinName);
119117
const txBytes = psbt.getHalfSignedLegacyFormat();
118+
const tx = Transaction.fromBytes(txBytes, coinName);
120119

121120
const reconstructed = BitGoPsbt.fromHalfSignedLegacyTransaction(
122-
txBytes,
121+
tx,
123122
coinName,
124123
rootWalletKeys,
125124
unspents,
@@ -152,13 +151,14 @@ describe("BitGoPsbt.fromHalfSignedLegacyTransaction", function () {
152151
psbt.sign(userXprv);
153152

154153
const txBytes = psbt.getHalfSignedLegacyFormat();
154+
const tx = Transaction.fromBytes(txBytes, "btc");
155155

156156
const unspents: HydrationUnspent[] = [
157157
{ chain: 0, index: 0, value: BigInt(10000) }, // wallet
158158
{ pubkey: ecpair.publicKey, value: BigInt(1000) }, // replay protection
159159
];
160160
const reconstructed = BitGoPsbt.fromHalfSignedLegacyTransaction(
161-
txBytes,
161+
tx,
162162
"btc",
163163
rootWalletKeys,
164164
unspents,
@@ -174,30 +174,31 @@ describe("BitGoPsbt.fromHalfSignedLegacyTransaction", function () {
174174
});
175175

176176
describe("Zcash legacy format round-trip", function () {
177-
it("should reject Zcash via dynamic dispatch in fromHalfSignedLegacyTransaction", function () {
178-
// With dynamic dispatch, fromHalfSignedLegacyTransaction now validates the transaction type
179-
// and rejects Zcash early with a clear error message, directing to ZcashBitGoPsbt.createEmpty().
177+
it("should reject Zcash via type check in fromHalfSignedLegacyTransaction", function () {
178+
// fromHalfSignedLegacyTransaction validates the transaction type at call time
179+
// and rejects Zcash with a clear error message.
180180
const rootWalletKeys = getDefaultWalletKeys();
181-
const { psbt: zcashPsbt, unspents } = createHalfSignedP2msPsbt(utxolib.networks.zcash);
181+
const { psbt: zcashPsbt, unspents } = createHalfSignedP2msPsbt("zec");
182182

183183
// Step 1: Extract Zcash PSBT as legacy format
184184
const txBytes = zcashPsbt.getHalfSignedLegacyFormat();
185185
assert.ok(txBytes.length > 0, "ZcashBitGoPsbt.getHalfSignedLegacyFormat() produces bytes");
186186

187-
// Step 2: Call fromHalfSignedLegacyTransaction with Zcash bytes
188-
// Expected: Throws clear error after detecting Zcash transaction via dynamic dispatch
189-
assert.throws(
190-
() => {
191-
BitGoPsbt.fromHalfSignedLegacyTransaction(txBytes, "zec", rootWalletKeys, unspents);
192-
},
193-
/Use ZcashBitGoPsbt.fromHalfSignedLegacyTransaction\(\) for Zcash transactions/,
194-
);
187+
// Step 2: Parse the transaction (will be ZcashTransaction)
188+
const tx = Transaction.fromBytes(txBytes, "zec");
189+
assert.ok(tx instanceof ZcashTransaction, "Parsed transaction is ZcashTransaction");
190+
191+
// Step 3: Call fromHalfSignedLegacyTransaction with Zcash transaction
192+
// Expected: Throws clear error after detecting Zcash transaction
193+
assert.throws(() => {
194+
BitGoPsbt.fromHalfSignedLegacyTransaction(tx, "zec", rootWalletKeys, unspents);
195+
}, /Use ZcashBitGoPsbt.fromHalfSignedLegacyTransaction\(\) for Zcash transactions/);
195196
});
196197

197198
it("should round-trip Zcash PSBT via ZcashBitGoPsbt.fromHalfSignedLegacyTransaction (with blockHeight)", function () {
198199
// This test verifies the round-trip: create Zcash PSBT → extract legacy format → reconstruct PSBT
199200
const rootWalletKeys = getDefaultWalletKeys();
200-
const { psbt, unspents } = createHalfSignedP2msPsbt(utxolib.networks.zcash);
201+
const { psbt, unspents } = createHalfSignedP2msPsbt("zec");
201202

202203
// Step 1: Extract half-signed legacy format (this is what would be transmitted)
203204
const legacyBytes = psbt.getHalfSignedLegacyFormat();
@@ -227,7 +228,7 @@ describe("BitGoPsbt.fromHalfSignedLegacyTransaction", function () {
227228
it("should round-trip Zcash PSBT via ZcashBitGoPsbt.fromHalfSignedLegacyTransaction (with consensusBranchId)", function () {
228229
// This test verifies the round-trip with explicit consensus branch ID instead of block height
229230
const rootWalletKeys = getDefaultWalletKeys();
230-
const { psbt, unspents } = createHalfSignedP2msPsbt(utxolib.networks.zcash);
231+
const { psbt, unspents } = createHalfSignedP2msPsbt("zec");
231232

232233
// Step 1: Extract half-signed legacy format
233234
const legacyBytes = psbt.getHalfSignedLegacyFormat();
@@ -254,26 +255,22 @@ describe("BitGoPsbt.fromHalfSignedLegacyTransaction", function () {
254255
assert.ok(serialized.length > 0, "Reconstructed Zcash PSBT serializes without error");
255256
});
256257

257-
it("should accept pre-decoded transaction instance to avoid re-parsing", function () {
258-
// Dynamic dispatch enhancement: fromHalfSignedLegacyTransaction now accepts
259-
// either txBytes OR a pre-decoded ITransaction instance
258+
it("should accept pre-decoded transaction instance", function () {
259+
// fromHalfSignedLegacyTransaction accepts a pre-decoded Transaction instance.
260+
// This is more efficient than parsing bytes twice.
260261
const rootWalletKeys = getDefaultWalletKeys();
261-
const { psbt, unspents } = createHalfSignedP2msPsbt(utxolib.networks.bitcoin);
262+
const { psbt, unspents } = createHalfSignedP2msPsbt("btc");
262263
const txBytes = psbt.getHalfSignedLegacyFormat();
263264

264-
// Method 1: Pass raw bytes (uses dynamic dispatch internally)
265-
const psbt1 = BitGoPsbt.fromHalfSignedLegacyTransaction(
266-
txBytes,
267-
"btc",
268-
rootWalletKeys,
269-
unspents,
270-
);
265+
// Parse transaction once and pass the instance
266+
const tx = Transaction.fromBytes(txBytes, "btc");
267+
const psbt1 = BitGoPsbt.fromHalfSignedLegacyTransaction(tx, "btc", rootWalletKeys, unspents);
271268

272-
// Method 2: Pre-decode transaction and pass instance (avoids re-parsing)
273-
const tx = Transaction.fromBytes(txBytes);
274-
const psbt2 = BitGoPsbt.fromHalfSignedLegacyTransaction(tx, "btc", rootWalletKeys, unspents);
269+
// Parse again to compare
270+
const tx2 = Transaction.fromBytes(txBytes, "btc");
271+
const psbt2 = BitGoPsbt.fromHalfSignedLegacyTransaction(tx2, "btc", rootWalletKeys, unspents);
275272

276-
// Both methods should produce equivalent results
273+
// Both should produce equivalent results
277274
assert.strictEqual(psbt1.inputCount(), psbt2.inputCount(), "Same input count");
278275
assert.strictEqual(psbt1.outputCount(), psbt2.outputCount(), "Same output count");
279276
assert.deepStrictEqual(psbt1.serialize(), psbt2.serialize(), "Identical serialization");

0 commit comments

Comments
 (0)