Skip to content

fix(mock-chain): don't mutate the caller's transaction in MockChain.execute() - #231

Open
Kshot3000 wants to merge 1 commit into
fleet-sdk:masterfrom
Kshot3000:fix/mock-chain-execute-output-mutation
Open

Kshot3000 wants to merge 1 commit into
fleet-sdk:masterfrom
Kshot3000:fix/mock-chain-execute-output-mutation

Conversation

@Kshot3000

Copy link
Copy Markdown

Summary

MockChain.execute() distributed a transaction's outputs to the parties by splicing the transaction's own outputs array:

const { inputs, outputs } = txObject;
for (const party of this.#parties) {
  for (let i = outputs.length - 1; i >= 0; i--) {
    if (party.ergoTree === outputs[i].ergoTree) {
      party.utxos.add(outputs[i]);
      outputs.splice(i, 1);
    }
  }
}

That is invisible when the transaction is passed as an ErgoUnsignedTransaction (a fresh EIP-12 object is built internally), but execute() also accepts a plain EIP12UnsignedTransaction — and then txObject is the caller's object. After execution, the caller's transaction had lost every output that matched a party — typically all of them — so inspecting the transaction afterwards, asserting on its outputs, or reusing the object operated on a truncated transaction.

Reproduced with a payment + change transaction passed via .toEIP12Object(): tx.outputs.length went from 3 before execute() to 1 after it (only the fee output, which matched no party in that setup, survived).

Fix

Distribute over a copy (const outputs = [...txObject.outputs]). Delivery semantics are unchanged: same parties, same order, each output still goes to at most one party.

Tests

  • New spec in mockChain.spec.ts: executes an EIP-12 transaction and asserts the caller's outputs (length, contents, and element identity) and inputs are unchanged, while the payment and change balances are still delivered correctly. It fails on master with exactly the mutation above (expected length 3, got 1) and passes with the fix.
  • Full monorepo suite: 1133/1133 tests pass (66 files; master baseline 1132 + the 1 new test).
  • Biome check clean on the changed files.

Includes a patch changeset for @fleet-sdk/mock-chain.


Built by Kyle Cox (@Kshot9000) — https://x.com/kshot9000
Tips (ERG): 9fcM5RWnAjmP4vx5bnW6yohB6H9bLq8sJbaPLHtwZLtQPB32Pvy

…xecute()

Outputs were distributed to parties by splicing the transaction's own
outputs array. When the transaction was passed as an EIP-12 object, the
caller's object lost every output that matched a party (typically all
of them), so inspecting or reusing it after execution saw a truncated
transaction. Distribute over a copy instead.
@changeset-bot

changeset-bot Bot commented Oct 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e77bd0c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@fleet-sdk/mock-chain Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant