Skip to content

fix(zetaclient): return early in Bitcoin refreshPendingNonce when pending nonces query fails - #4644

Open
eastagiletracker wants to merge 2 commits into
zeta-chain:mainfrom
eastagiletracker:agile-board/btc-refresh-pending-nonce-nil-guard
Open

eastagiletracker wants to merge 2 commits into
zeta-chain:mainfrom
eastagiletracker:agile-board/btc-refresh-pending-nonce-nil-guard

Conversation

@eastagiletracker

@eastagiletracker eastagiletracker commented Sep 30, 2026 •

Copy link
Copy Markdown

This PR proposes a fix for the nil pointer dereference in the Bitcoin observer's refreshPendingNonce when the pending nonces query to zetacore fails (Fixes #4412). We include this PR work along with a full history of your repo at https://eastagiletracker.com/projects/779. You can sign in with your GitHub ID to claim ownership of the project.

Description

refreshPendingNonce in zetaclient/chains/bitcoin/observer/outbound.go logs the error from ZetaRepo().GetPendingNonces but then falls through and reads p.NonceLow. On error GetPendingNonces returns a nil *PendingNonces, so the function panics. It runs at the top of FetchUTXOs, which is both the fetch_utxos interval task registered in zetaclient/chains/bitcoin/bitcoin.go and the first step of signer.SignWithdrawTx, so a single failed zetacore query aborts that tick (the panic is recovered by the ticker, as the chaos-mode log in the issue shows). The fix is the one described in the issue: return right after logging the error, leaving the artificial pending nonce as it was. The other GetPendingNonces callers (mempool.go, the EVM scheduler, the batch signer) already return on error, so Bitcoin's refreshPendingNonce was the only place with this pattern.

Reproduction on current main (4ceb665), with a mocked GetPendingNoncesByChain that returns an error:

$ go test ./zetaclient/chains/bitcoin/observer/ -run 'Test_FetchUTXOsPendingNoncesError|Test_RefreshPendingNonce' -count=1
{"level":"error","chain":8332,"network":"btc","module":"outbound","error":"error calling a zetacore client function (failed to get pending nonces): failed to get pending nonces"}
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	.../zetaclient/chains/bitcoin/observer/outbound.go:222 +0xb3
FAIL	github.com/zeta-chain/node/zetaclient/chains/bitcoin/observer

How Has This Been Tested?

  • Go unit tests

Added Test_FetchUTXOsPendingNoncesError (UTXOs are still fetched and the pending nonce is unchanged when zetacore errors) and a table-driven Test_RefreshPendingNonce (nonce raised when lagging, never lowered, kept on error). Both panic without the one-line change and pass with it. go test ./zetaclient/chains/bitcoin/... is green before and after the change (client, common, observer, signer), and go vet is clean on the observer package.

How this was managed

This work was tracked as Minor zetaclient nil pointer dereference on a board imported from this repository's issues and pull requests (4,504 stories), which we used to manage the fix: https://eastagiletracker.com/projects/779

board

If you'd rather not receive contributions like this, reply no-more-prs on this pull request and we won't open any further ones on your repositories.


Lawrence W. Sinclair
CEO / East Agile
linkedin.com/in/lwsinclair/
eastagile.com


Note

Low Risk
Single early-return on an existing error path in Bitcoin outbound nonce refresh, with unit tests and no change to successful behavior.

Overview
Fixes a nil pointer panic in the Bitcoin observer when zetacore’s pending-nonces query fails. refreshPendingNonce now returns immediately after logging the error instead of reading p.NonceLow from a nil result, so the in-memory pending nonce is left unchanged.

That path runs at the start of FetchUTXOs, so a transient zetacore error no longer aborts UTXO refresh or withdraw signing for that tick.

New tests cover FetchUTXOs when pending nonces fail (UTXOs still load, nonce unchanged) and table-driven cases for refreshPendingNonce (catch-up when lagging, never lowering nonce, no change on error).

Reviewed by Cursor Bugbot for commit ff9f4da. Configure here.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable issue was identified.

Summary

The PR returns early when Bitcoin’s pending-nonces query fails, preventing a nil dereference while leaving the local pending nonce unchanged. It adds regression coverage for UTXO fetching and nonce refresh behavior.

Reviews (1) · Last reviewed commit: "fix(zetaclient): return early in Bitcoin..."

@eastagiletracker
eastagiletracker requested a review from a team as a code owner September 30, 2026 01:30

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

This branch has not been deployed

No deployments
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.

Minor zetaclient nil pointer dereference

1 participant