Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions api/v1alpha1/archive_types.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package v1alpha1

// ArchiveSpec configures an archive node (no pruning, full history).
// Archive nodes always bootstrap via Tendermint state sync then block sync
// to retain all historical data from that point forward.
// If SnapshotGeneration is set, the node also acts as a snapshotter.
// Archive nodes bootstrap via block sync from peers to retain all
// historical data. If SnapshotGeneration is set, the node also produces
// Tendermint state-sync snapshots for other nodes to bootstrap from.
type ArchiveSpec struct {
// SnapshotGeneration configures periodic snapshot creation and optional upload.
// +optional
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/node/plan_execution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func TestBuildPlan_Archive(t *testing.T) {
p, _ := planner.ForNode(node)
plan := mustBuildPlan(t, p, node)
got := taskTypes(plan)
want := []string{planner.TaskConfigureGenesis, planner.TaskConfigApply, planner.TaskDiscoverPeers, planner.TaskConfigureStateSync, planner.TaskConfigValidate, planner.TaskMarkReady}
want := []string{planner.TaskConfigureGenesis, planner.TaskConfigApply, planner.TaskDiscoverPeers, planner.TaskConfigValidate, planner.TaskMarkReady}
assertProgression(t, got, want)
}

Expand Down
6 changes: 1 addition & 5 deletions internal/planner/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,12 @@ func (p *archiveNodePlanner) Validate(node *seiv1alpha1.SeiNode) error {
}

func (p *archiveNodePlanner) BuildPlan(node *seiv1alpha1.SeiNode) (*seiv1alpha1.TaskPlan, error) {
return buildBasePlan(node, node.Spec.Peers, p.snapshotSource(), &task.ConfigApplyParams{
return buildBasePlan(node, node.Spec.Peers, nil, &task.ConfigApplyParams{
Mode: string(seiconfig.ModeArchive),
Overrides: mergeOverrides(mergeOverrides(commonOverrides(node), p.controllerOverrides(node)), node.Spec.Overrides),
})
}

func (p *archiveNodePlanner) snapshotSource() *seiv1alpha1.SnapshotSource {
return &seiv1alpha1.SnapshotSource{StateSync: &seiv1alpha1.StateSyncSource{}}
}

func (p *archiveNodePlanner) controllerOverrides(node *seiv1alpha1.SeiNode) map[string]string {
sg := node.Spec.Archive.SnapshotGeneration
if sg == nil {
Expand Down
130 changes: 130 additions & 0 deletions internal/planner/archive_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package planner

import (
"slices"
"testing"

seiconfig "github.com/sei-protocol/sei-config"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

seiv1alpha1 "github.com/sei-protocol/sei-k8s-controller/api/v1alpha1"
)

func TestArchivePlanner_BlockSyncProgression(t *testing.T) {
node := &seiv1alpha1.SeiNode{
ObjectMeta: metav1.ObjectMeta{Name: "archive-0", Namespace: "pacific-1"},
Spec: seiv1alpha1.SeiNodeSpec{
ChainID: "pacific-1",
Image: "seid:v6.4.1",
Archive: &seiv1alpha1.ArchiveSpec{},
},
}

p := &archiveNodePlanner{}
plan, err := p.BuildPlan(node)
if err != nil {
t.Fatalf("BuildPlan: %v", err)
}

types := make([]string, 0, len(plan.Tasks))
for _, task := range plan.Tasks {
types = append(types, task.Type)
}

// Archive nodes use the genesis (block sync) progression: no snapshot-restore, no state-sync
if slices.Contains(types, TaskSnapshotRestore) {
t.Error("archive plan should not contain snapshot-restore")
}
if slices.Contains(types, TaskConfigureStateSync) {
t.Error("archive plan should not contain configure-state-sync")
}

// Must contain the base genesis progression
for _, expected := range []string{TaskConfigureGenesis, TaskConfigApply, TaskConfigValidate, TaskMarkReady} {
if !slices.Contains(types, expected) {
t.Errorf("archive plan missing expected task %s, got %v", expected, types)
}
}
}

func TestArchivePlanner_WithPeers(t *testing.T) {
node := &seiv1alpha1.SeiNode{
ObjectMeta: metav1.ObjectMeta{Name: "archive-0", Namespace: "pacific-1"},
Spec: seiv1alpha1.SeiNodeSpec{
ChainID: "pacific-1",
Image: "seid:v6.4.1",
Archive: &seiv1alpha1.ArchiveSpec{},
Peers: []seiv1alpha1.PeerSource{
{Static: &seiv1alpha1.StaticPeerSource{Addresses: []string{"peer1@host:26656"}}},
},
},
}

p := &archiveNodePlanner{}
plan, err := p.BuildPlan(node)
if err != nil {
t.Fatalf("BuildPlan: %v", err)
}

types := make([]string, 0, len(plan.Tasks))
for _, task := range plan.Tasks {
types = append(types, task.Type)
}

if !slices.Contains(types, TaskDiscoverPeers) {
t.Errorf("archive plan with peers should contain discover-peers, got %v", types)
}
}

func TestArchivePlanner_SnapshotGenerationOverrides(t *testing.T) {
node := &seiv1alpha1.SeiNode{
ObjectMeta: metav1.ObjectMeta{Name: "archive-0", Namespace: "pacific-1"},
Spec: seiv1alpha1.SeiNodeSpec{
ChainID: "pacific-1",
Image: "seid:v6.4.1",
Archive: &seiv1alpha1.ArchiveSpec{
SnapshotGeneration: &seiv1alpha1.SnapshotGenerationConfig{
KeepRecent: 5,
},
},
},
}

p := &archiveNodePlanner{}
overrides := p.controllerOverrides(node)

if overrides == nil {
t.Fatal("expected overrides for snapshotGeneration, got nil")
}
if got := overrides[seiconfig.KeySnapshotKeepRecent]; got != "5" {
t.Errorf("snapshot-keep-recent = %q, want %q", got, "5")
}
if _, ok := overrides[seiconfig.KeySnapshotInterval]; !ok {
t.Error("expected snapshot-interval override to be set")
}
}

func TestArchivePlanner_NoSnapshotGenerationOverrides(t *testing.T) {
node := &seiv1alpha1.SeiNode{
ObjectMeta: metav1.ObjectMeta{Name: "archive-0", Namespace: "pacific-1"},
Spec: seiv1alpha1.SeiNodeSpec{
ChainID: "pacific-1",
Image: "seid:v6.4.1",
Archive: &seiv1alpha1.ArchiveSpec{},
},
}

p := &archiveNodePlanner{}
overrides := p.controllerOverrides(node)

if overrides != nil {
t.Errorf("expected nil overrides without snapshotGeneration, got %v", overrides)
}
}

func TestArchivePlanner_Mode(t *testing.T) {
p := &archiveNodePlanner{}
if got := p.Mode(); got != string(seiconfig.ModeArchive) {
t.Errorf("Mode() = %q, want %q", got, seiconfig.ModeArchive)
}
}
Loading