diff --git a/CHANGELOG.md b/CHANGELOG.md index 52894d9d00..60e06a1e86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix race on startup sync. [#3162](https://github.com/evstack/ev-node/pull/3162) +- Strict raft state. [#3167](https://github.com/evstack/ev-node/pull/3167) ## v1.0.0 diff --git a/pkg/raft/types.go b/pkg/raft/types.go index bb5c6728b2..968d9aa959 100644 --- a/pkg/raft/types.go +++ b/pkg/raft/types.go @@ -11,10 +11,10 @@ type RaftBlockState = pb.RaftBlockState // assertValid checks basic constraints but does not ensure that no gaps exist or chain continuity func assertValid(s *RaftBlockState, next *RaftBlockState) error { - if s.Height > next.Height { + if s.Height >= next.Height { return fmt.Errorf("invalid height: %d > %d", s.Height, next.Height) } - if s.Timestamp > next.Timestamp { + if s.Timestamp >= next.Timestamp { return fmt.Errorf("invalid timestamp: %d > %d", s.Timestamp, next.Timestamp) } return nil diff --git a/pkg/raft/types_test.go b/pkg/raft/types_test.go new file mode 100644 index 0000000000..bb22b5679f --- /dev/null +++ b/pkg/raft/types_test.go @@ -0,0 +1,56 @@ +package raft + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAssertValid(t *testing.T) { + specs := map[string]struct { + s *RaftBlockState + next *RaftBlockState + expErr bool + }{ + "ok": { + s: &RaftBlockState{Height: 10, Timestamp: 100}, + next: &RaftBlockState{Height: 11, Timestamp: 101}, + }, + "all equal": { + s: &RaftBlockState{Height: 10, Timestamp: 100}, + next: &RaftBlockState{Height: 10, Timestamp: 100}, + expErr: true, + }, + "equal height": { + s: &RaftBlockState{Height: 10, Timestamp: 100}, + next: &RaftBlockState{Height: 10, Timestamp: 101}, + expErr: true, + }, + "equal timestamp": { + s: &RaftBlockState{Height: 10, Timestamp: 100}, + next: &RaftBlockState{Height: 11, Timestamp: 100}, + expErr: true, + }, + "lower timestamp": { + s: &RaftBlockState{Height: 10, Timestamp: 101}, + next: &RaftBlockState{Height: 11, Timestamp: 100}, + expErr: true, + }, + "lower height": { + s: &RaftBlockState{Height: 11, Timestamp: 100}, + next: &RaftBlockState{Height: 10, Timestamp: 101}, + expErr: true, + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + err := assertValid(spec.s, spec.next) + if spec.expErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +}