Skip to content

fix(zetaclient): respect DisableTssBlockScan in Bitcoin observer#4597

Merged
skosito merged 4 commits into
mainfrom
respect-disable-tss-block-scan-in-btc-observer
May 19, 2026
Merged

fix(zetaclient): respect DisableTssBlockScan in Bitcoin observer#4597
skosito merged 4 commits into
mainfrom
respect-disable-tss-block-scan-in-btc-observer

Conversation

@skosito
Copy link
Copy Markdown
Member

@skosito skosito commented May 19, 2026

Description

Align the Bitcoin observer with the EVM observer (zetaclient/chains/evm/observer/inbound.go:190), which already honors ChainParams.DisableTssBlockScan to skip TSS-address block scanning.

Bitcoin's only inbound mechanism is direct transfers to the TSS address, so this flag effectively provides operators a per-chain inbound observation pause for Bitcoin, with no effect on the outbound/withdrawal flow.

Notes:

  • updateLastBlock still runs so node health monitoring is unaffected
  • LastBlockScanned does not advance while the flag is true; flipping it back to false will resume scanning from the last scanned block (re-scanning the pause window)
  • Toggling this flag requires coordinated zetaclient rollout across observers to avoid ballot finalization issues during the rollout window

How Has This Been Tested?

  • Tested CCTX in localnet
  • Tested in development environment
  • Go unit tests
  • Go integration tests
  • Tested via GitHub Actions

Note

Medium Risk
Changes Bitcoin inbound processing behavior by short-circuiting both block scanning and tracker-based voting when DisableTssBlockScan is enabled; misconfiguration could pause deposit observation and delay inbound finalization.

Overview
Bitcoin observer now respects ChainParams.DisableTssBlockScan by returning early from ObserveInbound (after updateLastBlock) and from observeInboundTrackers, effectively pausing all inbound deposit detection/voting while leaving outbound processing untouched.

Adds unit tests asserting that enabling the flag results in no RPC scanning/processing calls for both block-range scanning and inbound-tracker handling.

Reviewed by Cursor Bugbot for commit f011b7a. Configure here.

Greptile Summary

This PR aligns the Bitcoin observer with the EVM observer by honoring ChainParams.DisableTssBlockScan, short-circuiting ObserveInbound (after updateLastBlock) and observeInboundTrackers when the flag is set. Since Bitcoin's only inbound mechanism is direct TSS transfers, the flag acts as a full per-chain inbound pause without touching outbound/withdrawal processing.

  • inbound.go: Guard is placed after updateLastBlock so chain-tip health monitoring continues; LastBlockScanned does not advance while paused, enabling clean resume-from-last-scanned when the flag is cleared.
  • inbound_tracker.go: Both external (ProcessInboundTrackers) and internal (ProcessInternalTrackers) tracker paths respect the flag, preventing ballot submission for any tracker discovered during the pause window.
  • inbound_test.go: Two negative-pattern unit tests confirm no RPC scanning or voting occurs when the flag is enabled; the testify mock client would panic on any unexpected call, making the guard genuinely enforced by the test.

Confidence Score: 5/5

Safe to merge — the guard is correctly placed after health-monitoring, logging is in place, and tests enforce the early-return path.

The change is a targeted, well-scoped guard that mirrors existing EVM observer behavior. The flag position (after updateLastBlock, before any scanning) is correct, the sampled log makes the skip observable in production, and the unit tests use testify mock panics to enforce that no RPC calls are made when the flag is active. No existing code paths are modified; the only risk is the operational concern already documented in the PR description about coordinated rollout.

No files require special attention.

Important Files Changed

Filename Overview
zetaclient/chains/bitcoin/observer/inbound.go Adds a DisableTssBlockScan guard after updateLastBlock in ObserveInbound, correctly mirroring the EVM observer pattern while using a sampled logger to signal the skip.
zetaclient/chains/bitcoin/observer/inbound_tracker.go Adds a DisableTssBlockScan guard at the top of observeInboundTrackers, halting both external and internal tracker voting when the flag is set; logs include tracker_count and is_internal for observability.
zetaclient/chains/bitcoin/observer/inbound_test.go Adds two unit tests verifying early-return behavior when DisableTssBlockScan is true; newTestSuite already mocks GetBlockCount so updateLastBlock succeeds, and unmocked RPC methods would panic on unexpected calls — an effective negative-test pattern.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ObserveInbound called] --> B[updateLastBlock\nhealth monitoring continues]
    B --> C{DisableTssBlockScan?}
    C -- true --> D[Log sampled info\nreturn nil]
    C -- false --> E[Fetch fee rate\nGet scan ranges]
    E --> F[observeInboundInBlockRange\nSafe blocks]
    F --> G[SaveLastBlockScanned]
    E --> H[observeInboundInBlockRange\nFast blocks]

    I[ProcessInboundTrackers called] --> J[GetInboundTrackers from ZetaRepo]
    J --> K[observeInboundTrackers\nisInternal=false]
    K --> L{DisableTssBlockScan?}
    L -- true --> M[Log sampled info\nreturn nil]
    L -- false --> N[CheckReceiptAndPostVoteForBtcTxHash\nfor each tracker]

    O[ProcessInternalTrackers called] --> P[GetInboundInternalTrackers]
    P --> Q[observeInboundTrackers\nisInternal=true]
    Q --> L
Loading

Reviews (2): Last reviewed commit: "changelog" | Re-trigger Greptile

@skosito skosito requested a review from a team as a code owner May 19, 2026 00:10
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a conditional disable mechanism for inbound Bitcoin block scanning. When the DisableTssBlockScan flag is enabled in chain parameters, both ObserveInbound and observeInboundTrackers short-circuit and return immediately, preventing inbound block-range scans and tracker observations. The implementation includes unit test coverage verifying the flag behavior.

Changes

Bitcoin inbound TSS block scanning disable

Layer / File(s) Summary
ObserveInbound and observeInboundTrackers disable guard
zetaclient/chains/bitcoin/observer/inbound.go, zetaclient/chains/bitcoin/observer/inbound_tracker.go
Early-return guards controlled by DisableTssBlockScan prevent SAFE/FAST inbound block scans and inbound tracker processing when the flag is enabled.
Test coverage for DisableTssBlockScan
zetaclient/chains/bitcoin/observer/inbound_test.go
Unit tests Test_ObserveInbound_DisableTssBlockScan and Test_ObserveInboundTrackers_DisableTssBlockScan verify that both methods return nil error and skip block/transaction retrieval logic when the flag is set.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: making Bitcoin observer respect DisableTssBlockScan, aligning it with existing EVM observer behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description provides comprehensive context, including alignment rationale with EVM observer, behavioral notes on updateLastBlock and LastBlockScanned, and operational considerations for coordinated rollout.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch respect-disable-tss-block-scan-in-btc-observer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread zetaclient/chains/bitcoin/observer/inbound_tracker.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
zetaclient/chains/bitcoin/observer/inbound_test.go (1)

146-160: ⚡ Quick win

Harden the guard tests with explicit “no processing” assertions.

require.NoError alone is broad. Add explicit assertions that no inbound-scan/tracker-processing side effect occurred (for example, unchanged scan state and/or zero receipt/vote path invocations) so regressions are caught deterministically.

Also applies to: 162-181

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@zetaclient/chains/bitcoin/observer/inbound_test.go` around lines 146 - 160,
Update Test_ObserveInbound_DisableTssBlockScan to assert no processing occurred
beyond returning no error: after setting DisableTssBlockScan on ob.ChainParams()
and calling ob.ObserveInbound(ob.ctx), assert the scan state remained unchanged
(e.g., compare previous and current scan height/marker from ob.ScanState or
equivalent) and assert the mock Bitcoin client received zero calls to
GetBlockHash/GetBlockVerbose and that tracker/receipt/vote handlers were not
invoked (use the mock call counters or expectations). Apply the same explicit
“no processing” assertions to the sibling test (the one at 162-181) so both
tests deterministically fail on regressions.
zetaclient/chains/bitcoin/observer/inbound.go (1)

29-34: ⚡ Quick win

Emit an explicit log when inbound scanning is disabled.

This branch is operationally significant; add a single info log before returning so pause/resume behavior is visible in production diagnostics.

Proposed patch
 if ob.ChainParams().DisableTssBlockScan {
+	logger.Info().
+		Bool("disable_tss_block_scan", true).
+		Uint64("last_block_scanned", ob.LastBlockScanned()).
+		Msg("skipping bitcoin inbound block scan by chain params")
 	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@zetaclient/chains/bitcoin/observer/inbound.go` around lines 29 - 34, Add an
info log before returning when inbound scanning is disabled: in the block that
checks ob.ChainParams().DisableTssBlockScan, emit a single info-level message
(e.g. using the observer's logger such as ob.logger or ob.Log.Infof/Info)
stating that TSS block scanning is disabled and inbound scanning is paused, then
return nil as before; use the existing ob receiver to find the correct logger
instance and keep the message concise for operational visibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@zetaclient/chains/bitcoin/observer/inbound_test.go`:
- Around line 146-160: Update Test_ObserveInbound_DisableTssBlockScan to assert
no processing occurred beyond returning no error: after setting
DisableTssBlockScan on ob.ChainParams() and calling ob.ObserveInbound(ob.ctx),
assert the scan state remained unchanged (e.g., compare previous and current
scan height/marker from ob.ScanState or equivalent) and assert the mock Bitcoin
client received zero calls to GetBlockHash/GetBlockVerbose and that
tracker/receipt/vote handlers were not invoked (use the mock call counters or
expectations). Apply the same explicit “no processing” assertions to the sibling
test (the one at 162-181) so both tests deterministically fail on regressions.

In `@zetaclient/chains/bitcoin/observer/inbound.go`:
- Around line 29-34: Add an info log before returning when inbound scanning is
disabled: in the block that checks ob.ChainParams().DisableTssBlockScan, emit a
single info-level message (e.g. using the observer's logger such as ob.logger or
ob.Log.Infof/Info) stating that TSS block scanning is disabled and inbound
scanning is paused, then return nil as before; use the existing ob receiver to
find the correct logger instance and keep the message concise for operational
visibility.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 23aab3cb-c115-4ef1-8248-af40671cc665

📥 Commits

Reviewing files that changed from the base of the PR and between 9a516a3 and f011b7a.

📒 Files selected for processing (3)
  • zetaclient/chains/bitcoin/observer/inbound.go
  • zetaclient/chains/bitcoin/observer/inbound_test.go
  • zetaclient/chains/bitcoin/observer/inbound_tracker.go

@ws4charlie
Copy link
Copy Markdown
Contributor

missing change log

@skosito
Copy link
Copy Markdown
Member Author

skosito commented May 19, 2026

@greptile

@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@skosito skosito added this pull request to the merge queue May 19, 2026
Merged via the queue into main with commit 501fd44 May 19, 2026
49 checks passed
@skosito skosito deleted the respect-disable-tss-block-scan-in-btc-observer branch May 19, 2026 17:31
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.

3 participants