Skip to content

fix(btcindexer): isolate minted and reorged txs by network#355

Merged
sczembor merged 13 commits intomasterfrom
stan/network-insolation
Feb 18, 2026
Merged

fix(btcindexer): isolate minted and reorged txs by network#355
sczembor merged 13 commits intomasterfrom
stan/network-insolation

Conversation

@sczembor
Copy link
Contributor

@sczembor sczembor commented Feb 11, 2026

Description

Closes: #342 #343 #344


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • added appropriate labels to the PR
  • provided a link to the relevant issue or specification
  • added a changelog entry to CHANGELOG.md
  • included doc comments for public functions
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary

Summary by Sourcery

Isolate nBTC minting and reorg handling by Bitcoin and Sui networks and extend tests to cover multi-network behaviour.

Bug Fixes:

  • Restrict minted transaction queries to specific Bitcoin/Sui network pairs to prevent cross-network leakage.
  • Ensure reorg detection and transaction status lookups are scoped to the correct Bitcoin network.

Enhancements:

  • Extend storage and indexer interfaces to accept explicit network parameters for minted transaction queries, reorg detection, and status checks.
  • Add network isolation unit tests covering minted transactions, reorged transactions, and transaction status across multiple networks.

Tests:

  • Add comprehensive network isolation tests for CFStorage and adjust existing indexer tests to use network-aware APIs.

Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
@sczembor sczembor requested a review from a team as a code owner February 11, 2026 19:29
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 11, 2026

Reviewer's Guide

Implements network isolation for minted transaction queries and reorg detection by threading explicit btc/sui network parameters through the storage and indexer layers, and adds tests to verify correct behavior across multiple networks.

Sequence diagram for network-isolated minted tx reorg detection

sequenceDiagram
    participant Indexer
    participant Storage
    participant D1Database

    Indexer->>Storage: getMintedTxs(blockHeight, btcNet, suiNet)
    Storage->>D1Database: SELECT minted txs WHERE block_height >= blockHeight AND btc_network = btcNet AND sui_network = suiNet
    D1Database-->>Storage: FinalizedTxRow[]
    Storage-->>Indexer: FinalizedTxRow[]

    loop each finalized tx in FinalizedTxRow[]
        Indexer->>Indexer: locate tx in block.transactions by tx_id
        alt tx not found in block
            Indexer->>Indexer: handleMissingFinalizedMintingTx(txId, btcNet)
            Indexer->>Storage: getTxStatus(txId, btcNet)
            Storage->>D1Database: SELECT status FROM nbtc_minting JOIN setups WHERE tx_id = txId AND btc_network = btcNet
            D1Database-->>Storage: MintTxStatus | null
            Storage-->>Indexer: MintTxStatus | null
            Indexer->>Storage: updateNbtcTxsStatus([txId], MintTxStatus.MintedReorg)
        else tx found
            Indexer->>Indexer: include tx in mint batch for its setup_id
        end
    end

    Indexer->>Storage: detectMintedReorgs(blockHeight, btcNet)
    Indexer->>Storage: getReorgedMintedTxs(blockHeight, btcNet)
    Storage->>D1Database: SELECT reorged minted txs WHERE block_height >= blockHeight AND btc_blocks.network = btcNet
    D1Database-->>Storage: ReorgedMintedTx[]
    Storage-->>Indexer: ReorgedMintedTx[]

    loop each reorged in ReorgedMintedTx[]
        Indexer->>Storage: updateNbtcTxsStatus([reorged.tx_id], MintTxStatus.MintedReorg)
    end
Loading

Class diagram for updated storage and indexer network isolation

classDiagram
    class Storage {
        <<interface>>
        +insertBlockInfo(blockInfo: BlockQueueRecord) Promise~InsertBlockStatus~
        +insertOrUpdateNbtcTxs(txs: NbtcTxInsertion[]) Promise~void~
        +getNbtcMintCandidates(maxRetries: number) Promise~FinalizedTxRow[]~
        +getMintedTxs(blockHeight: number, btcNet: BtcNet, suiNet: SuiNet) Promise~FinalizedTxRow[]~
        +getTxStatus(txId: string, btcNet: BtcNet) Promise~MintTxStatus | null~
        +getReorgedMintedTxs(blockHeight: number, btcNet: BtcNet) Promise~ReorgedMintedTx[]~
        +updateNbtcTxsStatus(txIds: string[], status: MintTxStatus) Promise~void~
        +batchUpdateNbtcMintTxs(updates: NbtcTxUpdate[]) Promise~void~
        +updateConfirmingTxsToReorg(blockHashes: string[]) Promise~void~
    }

    class CFStorage {
        -d1: D1Database
        +insertBlockInfo(blockInfo: BlockQueueRecord) Promise~InsertBlockStatus~
        +insertOrUpdateNbtcTxs(txs: NbtcTxInsertion[]) Promise~void~
        +getNbtcMintCandidates(maxRetries: number) Promise~FinalizedTxRow[]~
        +getMintedTxs(blockHeight: number, btcNet: BtcNet, suiNet: SuiNet) Promise~FinalizedTxRow[]~
        +getTxStatus(txId: string, btcNet: BtcNet) Promise~MintTxStatus | null~
        +getReorgedMintedTxs(blockHeight: number, btcNet: BtcNet) Promise~ReorgedMintedTx[]~
        +updateNbtcTxsStatus(txIds: string[], status: MintTxStatus) Promise~void~
        +batchUpdateNbtcMintTxs(updates: NbtcTxUpdate[]) Promise~void~
        +updateConfirmingTxsToReorg(blockHashes: string[]) Promise~void~
    }

    class Indexer {
        -storage: Storage
        +processBlock(blockInfo: BlockQueueRecord) Promise~boolean~
        +detectMintedReorgs(blockHeight: number, btcNet: BtcNet) Promise~void~
        -handleMissingFinalizedMintingTx(txId: string, btcNet: BtcNet) Promise~void~
        -getPackageConfig(setupId: number) PackageConfig
        -processMintedTxBatches(block: BlockQueueRecord, txs: FinalizedTxRow[]) Promise~void~
    }

    class FinalizedTxRow {
        +tx_id: string
        +vout: number
        +block_hash: string
        +block_height: number
        +nbtc_pkg: string
        +sui_network: SuiNet
        +btc_network: BtcNet
        +setup_id: number
    }

    class ReorgedMintedTx {
        +tx_id: string
        +old_block_hash: string
        +new_block_hash: string
        +block_height: number
    }

    class PackageConfig {
        +btc_network: BtcNet
        +sui_network: SuiNet
        +nbtc_pkg: string
        +nbtc_contract: string
        +lc_pkg: string
        +lc_contract: string
        +nbtc_fallback_addr: string
    }

    Storage <|.. CFStorage
    Indexer --> Storage
    CFStorage --> D1Database
    Indexer --> PackageConfig
    CFStorage --> FinalizedTxRow
    CFStorage --> ReorgedMintedTx
Loading

File-Level Changes

Change Details Files
Add explicit network scoping to minted transaction, reorg, and status queries in the storage layer.
  • Extend Storage interface methods getMintedTxs, getTxStatus, and getReorgedMintedTxs to accept BtcNet and/or SuiNet parameters.
  • Update CFStorage.getMintedTxs query to filter by btc_network and sui_network and return setup_id.
  • Update CFStorage.getReorgedMintedTxs query to join btc_blocks on network and filter by btc_network.
  • Update CFStorage.getTxStatus to join through deposit addresses and setups and filter by btc_network.
packages/btcindexer/src/storage.ts
packages/btcindexer/src/cf-storage.ts
Propagate network parameters through the indexer logic for reorg detection and missing finalized mint handling.
  • Change Indexer.processBlock to pass block network into detectMintedReorgs.
  • Update detectMintedReorgs to accept BtcNet and call storage.getReorgedMintedTxs with it.
  • Update handleMissingFinalizedMintingTx to accept BtcNet, fetch status via network-scoped getTxStatus, and adjust callers in finalizeMintingBatch to pass the correct network.
packages/btcindexer/src/btcindexer.ts
Extend and adjust unit tests to cover network-isolated behavior for minted tx queries, reorg detection, and status lookups.
  • Update existing tests to pass new network parameters into getMintedTxs, getReorgedMintedTxs, getTxStatus, and detectMintedReorgs.
  • Add a new Network Isolation test suite for CFStorage validating per-(btc,sui) isolation for getMintedTxs, per-btc isolation for getReorgedMintedTxs and getTxStatus.
  • Adjust Indexer tests to call the updated detectMintedReorgs and getTxStatus signatures with explicit BtcNet values.
packages/btcindexer/src/storage.test.ts
packages/btcindexer/src/btcindexer.test.ts

Assessment against linked issues

Issue Objective Addressed Explanation
#342 Update CFStorage.getMintedTxs so that it returns only minted transactions for a specific BTC/Sui network pair instead of all networks.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@sczembor
Copy link
Contributor Author

@sourcery-ai title

@sourcery-ai sourcery-ai bot changed the title netowrk insolation + unit tests fix(btcindexer): isolate minted and reorged txs by network Feb 11, 2026
sczembor and others added 5 commits February 16, 2026 13:40
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Signed-off-by: sczembor <43810037+sczembor@users.noreply.github.com>
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements network isolation for the Bitcoin indexer by introducing setupId as a parameter to isolate nBTC minting transactions, reorged transactions, and transaction status lookups across different Bitcoin/Sui network pairs. The changes address critical cross-network data leakage issues where transactions from one network could interfere with another.

Changes:

  • Extended storage and indexer interfaces to accept setupId parameter for all transaction queries and updates, replacing raw BtcNet parameters in several methods
  • Modified database schema to use composite primary key (tx_id, address_id) in nbtc_minting table, allowing the same Bitcoin transaction ID across different setups
  • Added comprehensive network isolation tests covering minted transactions, reorged transactions, and transaction status queries across multiple networks

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/btcindexer/src/storage.ts Updated Storage interface to add setupId parameter to transaction query methods
packages/btcindexer/src/cf-storage.ts Implemented network isolation in SQL queries using setupId filtering and JOIN conditions
packages/btcindexer/src/btcindexer.ts Updated business logic to propagate setupId throughout the codebase and handle reorgs per setup
packages/btcindexer/src/router.ts Added setupId query parameter validation for HTTP endpoints
packages/btcindexer/src/rpc.ts Updated RPC methods to accept setupId parameter
packages/btcindexer/src/rpc-mock.ts Updated mock RPC implementation signatures
packages/btcindexer/src/rpc-interface.ts Updated RPC interface method signatures
packages/btcindexer/src/models.ts Added setupId field to transaction models
packages/btcindexer/src/storage.test.ts Added comprehensive network isolation tests and updated existing tests
packages/btcindexer/src/btcindexer.test.ts Updated tests to pass setupId parameter
packages/btcindexer/src/btcindexer.helpers.test.ts Updated test helper to support optional setupId filtering
packages/btcindexer/db/migrations/0001_initial_schema.sql Changed PRIMARY KEY from tx_id to composite (tx_id, address_id)
packages/block-ingestor/README.md Minor markdown formatting improvements
AGENTS.md Minor markdown formatting and table alignment improvements

sczembor and others added 5 commits February 17, 2026 18:08
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.

Copy link
Contributor

@robert-zaremba robert-zaremba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approving, but I would prefer to not add setup_id to the objects when it's not necessary.

Signed-off-by: sczembor <stanislaw.czembor@gmail.com>
@sczembor sczembor enabled auto-merge (squash) February 18, 2026 13:45
@sczembor sczembor merged commit d54fd72 into master Feb 18, 2026
12 checks passed
@sczembor sczembor deleted the stan/network-insolation branch February 18, 2026 13:46
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.

worker: Network Isolation: Minted Transactions

3 participants