Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2d28b20
Fix raft leader handoff regression after SIGTERM
auricom Apr 7, 2026
857b44b
Merge branch 'main' into fix/3229-raft-re-election
auricom Apr 8, 2026
2106f04
fix: follower crash on restart when EVM is ahead of stale raft snapshot
auricom Apr 8, 2026
52d7cda
fix(raft): guard FSM apply callback with RWMutex to prevent data race
auricom Apr 8, 2026
b8471f0
feat(raft): add ResignLeader() public method on Node
auricom Apr 9, 2026
c6b1a5f
feat(node): implement LeaderResigner interface on FullNode
auricom Apr 9, 2026
4cdfc54
fix(shutdown): resign raft leadership before cancelling context on SI…
auricom Apr 9, 2026
266c61f
feat(config): add election_timeout, snapshot_threshold, trailing_logs…
auricom Apr 9, 2026
cc39c9a
fix(raft): wire snapshot_threshold, trailing_logs, election_timeout i…
auricom Apr 9, 2026
135b5af
feat(raft): annotate FSM apply log and RaftApplyMsg with raft term fo…
auricom Apr 9, 2026
465203e
fix(ci): fix gci comment alignment in defaults.go; remove boltdb-trig…
auricom Apr 9, 2026
84b70d4
fix(raft): suppress boltdb 'Rollback failed: tx closed' log noise
auricom Apr 10, 2026
30ef514
fix(raft): address PR review — shutdown wiring, error logging, snap d…
auricom Apr 10, 2026
3d94b75
fix(raft): address code review issues — ShutdownTimeout, resign fence…
auricom Apr 10, 2026
9ed4946
style(raft): fix gci struct field alignment in node_test.go
auricom Apr 10, 2026
a2a2599
test: improve patch coverage for raft shutdown and resign paths
auricom Apr 10, 2026
4d105a2
fix(config): reject negative ElectionTimeout in RaftConfig.Validate
auricom Apr 10, 2026
fc023b8
fix(raft): preserve stdlib logger writer in bolt filter; propagate ct…
auricom Apr 10, 2026
2d3dc8e
fix(node): propagate context through LeaderResigner.ResignLeader inte…
auricom Apr 10, 2026
40b7251
fix(raft): abdicate leadership when store is significantly behind raf…
auricom Apr 15, 2026
bf6bb50
fix(raft): address julienrbrt review — logger, boltdb filter, Shutdow…
auricom Apr 15, 2026
f90c600
fix(ci): promote go-hclog to direct dep; fix gci alignment in syncer_…
auricom Apr 15, 2026
7e09507
Merge branch 'main' into fix/3229-raft-re-election
auricom Apr 15, 2026
0f6818f
fix(raft): address coderabbitai feedback — ShutdownTimeout clamp, tra…
auricom Apr 15, 2026
84ec0d0
docs(changelog): add unreleased entries for raft HA hardening (#3230)
auricom Apr 15, 2026
5897ef3
fix(raft): wait for block-store sync before abdicating on leader elec…
auricom Apr 17, 2026
03e33c3
Merge branch 'main' into fix/3229-raft-re-election
auricom Apr 20, 2026
f61de99
fix(raft): distinguish sync wait outcomes with syncResult enum
auricom Apr 20, 2026
a434761
fix(raft): fix gci alignment in syncResult const block
auricom Apr 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions block/internal/syncing/raft_retriever.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func (r *raftRetriever) Stop() {
r.mtx.Unlock()

r.wg.Wait()
r.raftNode.SetApplyCallback(nil)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// raftApplyLoop processes blocks received from raft
Expand Down
61 changes: 61 additions & 0 deletions block/internal/syncing/raft_retriever_test.go
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this test does not look necessary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — deleted in bf6bb50. The test was validating an implementation detail (that Stop() calls SetApplyCallback(nil)) rather than observable behaviour. The stubRaftNode helper it defined has been moved to syncer_test.go where it's still needed by TestSyncer_Stop_CallsRaftRetrieverStop.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package syncing

import (
"context"
"sync"
"testing"

"github.com/rs/zerolog"
"github.com/stretchr/testify/require"

"github.com/evstack/ev-node/pkg/genesis"
pkgraft "github.com/evstack/ev-node/pkg/raft"
)

type stubRaftNode struct {
mu sync.Mutex
callbacks []chan<- pkgraft.RaftApplyMsg
}

func (s *stubRaftNode) IsLeader() bool { return false }

func (s *stubRaftNode) HasQuorum() bool { return false }

func (s *stubRaftNode) GetState() *pkgraft.RaftBlockState { return nil }

func (s *stubRaftNode) Broadcast(context.Context, *pkgraft.RaftBlockState) error { return nil }

func (s *stubRaftNode) SetApplyCallback(ch chan<- pkgraft.RaftApplyMsg) {
s.mu.Lock()
defer s.mu.Unlock()
s.callbacks = append(s.callbacks, ch)
}

func (s *stubRaftNode) recordedCallbacks() []chan<- pkgraft.RaftApplyMsg {
s.mu.Lock()
defer s.mu.Unlock()
out := make([]chan<- pkgraft.RaftApplyMsg, len(s.callbacks))
copy(out, s.callbacks)
return out
}

func TestRaftRetrieverStopClearsApplyCallback(t *testing.T) {
t.Parallel()

raftNode := &stubRaftNode{}
retriever := newRaftRetriever(
raftNode,
genesis.Genesis{},
zerolog.Nop(),
nil,
func(context.Context, *pkgraft.RaftBlockState) error { return nil },
)

require.NoError(t, retriever.Start(t.Context()))
retriever.Stop()

callbacks := raftNode.recordedCallbacks()
require.Len(t, callbacks, 2)
require.NotNil(t, callbacks[0])
require.Nil(t, callbacks[1])
}
2 changes: 1 addition & 1 deletion pkg/raft/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (n *Node) waitForMsgsLanded(timeout time.Duration) error {
for {
select {
case <-ticker.C:
if n.raft.AppliedIndex() >= n.raft.LastIndex() {
if n.raft.AppliedIndex() >= n.raft.CommitIndex() {
return nil
}
case <-timeoutTicker.C:
Expand Down
Loading