Skip to content

Fix off-by-one in PushBlock that causes nil dereference panic#2924

Merged
wen-coding merged 4 commits intomainfrom
wen/fix_pushblock_verify
Feb 20, 2026
Merged

Fix off-by-one in PushBlock that causes nil dereference panic#2924
wen-coding merged 4 commits intomainfrom
wen/fix_pushblock_verify

Conversation

@wen-coding
Copy link
Contributor

@wen-coding wen-coding commented Feb 18, 2026

Summary

  • Fix off-by-one in PushBlock: The WaitUntil condition used n <= inner.nextQC, which allows PushBlock to proceed when n == nextQC. Since inner.qcs stores entries for the half-open range [first, nextQC), the map lookup returns nil, and the subsequent qc.Headers() call panics with a nil pointer dereference. Changed to n < inner.nextQC to match every other waiter in the file (QC, Block, GlobalBlock, AppProposal).

@github-actions
Copy link

github-actions bot commented Feb 18, 2026

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedFeb 20, 2026, 2:46 AM

@codecov
Copy link

codecov bot commented Feb 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.64%. Comparing base (4d45fcd) to head (e923016).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2924      +/-   ##
==========================================
+ Coverage   68.42%   68.64%   +0.21%     
==========================================
  Files           5        5              
  Lines         456      456              
==========================================
+ Hits          312      313       +1     
+ Misses        114      113       -1     
  Partials       30       30              
Flag Coverage Δ
sei-db 68.64% <ø> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pompon0 pompon0 self-requested a review February 19, 2026 10:07
"github.com/sei-protocol/sei-chain/sei-tendermint/internal/autobahn/types"
"github.com/sei-protocol/sei-chain/sei-tendermint/libs/utils"
"github.com/sei-protocol/sei-chain/sei-tendermint/libs/utils/scope"
"github.com/stretchr/testify/require"
Copy link
Contributor

Choose a reason for hiding this comment

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

libs/utils/require. It contains a strongly typed wrappers of testify/require. If you are missing any wrappers, you can add them there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done.

_, err := state.TryBlock(gr2.First)
require.ErrorIs(t, err, ErrNotFound)

// PushBlock for a block in qc2's range. With the off-by-one bug
Copy link
Contributor

@pompon0 pompon0 Feb 19, 2026

Choose a reason for hiding this comment

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

nit: scope.Run?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

// (n <= inner.nextQC), this would immediately dereference a nil QC
// pointer and panic. With the fix, it waits for the QC.
errc := make(chan error, 1)
go func() {
Copy link
Contributor

Choose a reason for hiding this comment

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

this looks like a great use case for https://go.dev/blog/synctest . Do you want to give it a try?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done.

@wen-coding wen-coding requested a review from arajasek February 19, 2026 19:11
@wen-coding wen-coding enabled auto-merge (squash) February 19, 2026 22:24
wen-coding and others added 4 commits February 19, 2026 18:43
PushBlock's WaitUntil used n <= inner.nextQC, allowing it to proceed
when n == nextQC. Since inner.qcs stores [first, nextQC), the lookup
returns nil, causing a panic on qc.Headers(). Changed to n < nextQC
to match every other waiter in the file. Added defense-in-depth nil
check with a descriptive error message.

Co-authored-by: Cursor <cursoragent@cursor.com>
WaitUntil(n < nextQC) guarantees inner.qcs[n] is non-nil, making the
defense-in-depth nil check dead code that triggers coverage complaints.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace manual goroutine + channel pattern with synctest.Test/Wait,
enabling a stronger intermediate assertion that the block is absent
while PushBlock is blocked. Also switch to libs/utils/require.

Co-authored-by: Cursor <cursoragent@cursor.com>
TestPushBlockAcceptsBlockWithQC exercises PushBlock outside a synctest
bubble so coverage instrumentation records the changed line.

Co-authored-by: Cursor <cursoragent@cursor.com>
@wen-coding wen-coding force-pushed the wen/fix_pushblock_verify branch from 812e0d1 to e923016 Compare February 20, 2026 02:45
@wen-coding wen-coding merged commit 933111a into main Feb 20, 2026
37 of 38 checks passed
@wen-coding wen-coding deleted the wen/fix_pushblock_verify branch February 20, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants