1+ package block
2+
3+ import (
4+ "context"
5+ "sync"
6+ "testing"
7+ "time"
8+
9+ logging "github.com/ipfs/go-log/v2"
10+ "github.com/stretchr/testify/assert"
11+ "github.com/stretchr/testify/mock"
12+ "github.com/stretchr/testify/require"
13+
14+ "github.com/rollkit/rollkit/pkg/config"
15+ "github.com/rollkit/rollkit/pkg/genesis"
16+ "github.com/rollkit/rollkit/test/mocks"
17+ "github.com/rollkit/rollkit/types"
18+ )
19+
20+ func TestManager_RollbackLastBlock (t * testing.T ) {
21+ tests := []struct {
22+ name string
23+ currentHeight uint64
24+ expectError bool
25+ expectedErrorMsg string
26+ setupMocks func (* mocks.MockStore , * mocks.MockExecutor )
27+ }{
28+ {
29+ name : "cannot rollback genesis block" ,
30+ currentHeight : 1 ,
31+ expectError : true ,
32+ expectedErrorMsg : "cannot rollback from height 1: must be > 1" ,
33+ setupMocks : func (mockStore * mocks.MockStore , mockExec * mocks.MockExecutor ) {
34+ // No mocks needed as error should be returned early
35+ },
36+ },
37+ {
38+ name : "successful rollback from height 2" ,
39+ currentHeight : 2 ,
40+ expectError : false ,
41+ setupMocks : func (mockStore * mocks.MockStore , mockExec * mocks.MockExecutor ) {
42+ prevStateRoot := []byte {1 , 2 , 3 , 4 }
43+ prevState := types.State {
44+ ChainID : "test-chain" ,
45+ LastBlockHeight : 1 ,
46+ LastBlockTime : time .Now ().Add (- time .Minute ),
47+ AppHash : prevStateRoot ,
48+ }
49+
50+ // Mock executor rollback
51+ mockExec .On ("Rollback" , mock .Anything , uint64 (2 )).Return (prevStateRoot , nil )
52+
53+ // Mock store rollback
54+ mockStore .On ("RollbackToHeight" , mock .Anything , uint64 (1 )).Return (nil )
55+
56+ // Mock getting state after rollback
57+ mockStore .On ("GetState" , mock .Anything ).Return (prevState , nil )
58+
59+ // Mock getting header for cache cleanup
60+ mockStore .On ("GetHeader" , mock .Anything , uint64 (2 )).Return (nil , assert .AnError )
61+ },
62+ },
63+ {
64+ name : "executor rollback fails" ,
65+ currentHeight : 3 ,
66+ expectError : true ,
67+ expectedErrorMsg : "failed to rollback execution layer" ,
68+ setupMocks : func (mockStore * mocks.MockStore , mockExec * mocks.MockExecutor ) {
69+ // Mock executor rollback failure
70+ mockExec .On ("Rollback" , mock .Anything , uint64 (3 )).Return (nil , assert .AnError )
71+ },
72+ },
73+ {
74+ name : "store rollback fails" ,
75+ currentHeight : 2 ,
76+ expectError : true ,
77+ expectedErrorMsg : "failed to rollback store" ,
78+ setupMocks : func (mockStore * mocks.MockStore , mockExec * mocks.MockExecutor ) {
79+ prevStateRoot := []byte {1 , 2 , 3 , 4 }
80+
81+ // Mock executor rollback success
82+ mockExec .On ("Rollback" , mock .Anything , uint64 (2 )).Return (prevStateRoot , nil )
83+
84+ // Mock store rollback failure
85+ mockStore .On ("RollbackToHeight" , mock .Anything , uint64 (1 )).Return (assert .AnError )
86+ },
87+ },
88+ }
89+
90+ for _ , tt := range tests {
91+ t .Run (tt .name , func (t * testing.T ) {
92+ // Setup mocks
93+ mockStore := mocks .NewMockStore (t )
94+ mockExec := mocks .NewMockExecutor (t )
95+
96+ // Setup the specific mocks for this test
97+ tt .setupMocks (mockStore , mockExec )
98+
99+ // Create manager with mocks
100+ manager := & Manager {
101+ lastState : types.State {
102+ ChainID : "test-chain" ,
103+ LastBlockHeight : tt .currentHeight ,
104+ LastBlockTime : time .Now (),
105+ AppHash : []byte {5 , 6 , 7 , 8 },
106+ },
107+ lastStateMtx : & sync.RWMutex {},
108+ store : mockStore ,
109+ exec : mockExec ,
110+ config : config.Config {},
111+ genesis : genesis.Genesis {},
112+ logger : logging .Logger ("test" ),
113+ }
114+
115+ // Set DA included height to current height for testing
116+ manager .daIncludedHeight .Store (tt .currentHeight )
117+
118+ // Execute rollback
119+ err := manager .RollbackLastBlock (context .Background ())
120+
121+ // Verify results
122+ if tt .expectError {
123+ require .Error (t , err )
124+ if tt .expectedErrorMsg != "" {
125+ assert .Contains (t , err .Error (), tt .expectedErrorMsg )
126+ }
127+ } else {
128+ require .NoError (t , err )
129+
130+ // Verify state was updated
131+ assert .Equal (t , uint64 (1 ), manager .lastState .LastBlockHeight )
132+
133+ // Verify DA included height was updated
134+ assert .Equal (t , uint64 (1 ), manager .daIncludedHeight .Load ())
135+ }
136+ })
137+ }
138+ }
0 commit comments