github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/ibft/core/backlog_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "math/big" 21 "reflect" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/kisexp/xdchain/common" 27 "github.com/kisexp/xdchain/consensus/istanbul" 28 istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common" 29 ibfttypes "github.com/kisexp/xdchain/consensus/istanbul/ibft/types" 30 "github.com/kisexp/xdchain/event" 31 "github.com/kisexp/xdchain/log" 32 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 33 ) 34 35 func TestCheckMessage(t *testing.T) { 36 c := &core{ 37 state: ibfttypes.StateAcceptRequest, 38 current: newRoundState(&istanbul.View{ 39 Sequence: big.NewInt(1), 40 Round: big.NewInt(0), 41 }, newTestValidatorSet(4), common.Hash{}, nil, nil, nil), 42 } 43 44 // invalid view format 45 err := c.checkMessage(ibfttypes.MsgPreprepare, nil) 46 if err != istanbulcommon.ErrInvalidMessage { 47 t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrInvalidMessage) 48 } 49 50 testStates := []ibfttypes.State{ibfttypes.StateAcceptRequest, ibfttypes.StatePreprepared, ibfttypes.StatePrepared, ibfttypes.StateCommitted} 51 testCode := []uint64{ibfttypes.MsgPreprepare, ibfttypes.MsgPrepare, ibfttypes.MsgCommit, ibfttypes.MsgRoundChange} 52 53 // future sequence 54 v := &istanbul.View{ 55 Sequence: big.NewInt(2), 56 Round: big.NewInt(0), 57 } 58 for i := 0; i < len(testStates); i++ { 59 c.state = testStates[i] 60 for j := 0; j < len(testCode); j++ { 61 err := c.checkMessage(testCode[j], v) 62 if err != istanbulcommon.ErrFutureMessage { 63 t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrFutureMessage) 64 } 65 } 66 } 67 68 // future round 69 v = &istanbul.View{ 70 Sequence: big.NewInt(1), 71 Round: big.NewInt(1), 72 } 73 for i := 0; i < len(testStates); i++ { 74 c.state = testStates[i] 75 for j := 0; j < len(testCode); j++ { 76 err := c.checkMessage(testCode[j], v) 77 if testCode[j] == ibfttypes.MsgRoundChange { 78 if err != nil { 79 t.Errorf("error mismatch: have %v, want nil", err) 80 } 81 } else if err != istanbulcommon.ErrFutureMessage { 82 t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrFutureMessage) 83 } 84 } 85 } 86 87 // current view but waiting for round change 88 v = &istanbul.View{ 89 Sequence: big.NewInt(1), 90 Round: big.NewInt(0), 91 } 92 c.waitingForRoundChange = true 93 for i := 0; i < len(testStates); i++ { 94 c.state = testStates[i] 95 for j := 0; j < len(testCode); j++ { 96 err := c.checkMessage(testCode[j], v) 97 if testCode[j] == ibfttypes.MsgRoundChange { 98 if err != nil { 99 t.Errorf("error mismatch: have %v, want nil", err) 100 } 101 } else if err != istanbulcommon.ErrFutureMessage { 102 t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrFutureMessage) 103 } 104 } 105 } 106 c.waitingForRoundChange = false 107 108 v = c.currentView() 109 // current view, state = ibfttypes.StateAcceptRequest 110 c.state = ibfttypes.StateAcceptRequest 111 for i := 0; i < len(testCode); i++ { 112 err = c.checkMessage(testCode[i], v) 113 if testCode[i] == ibfttypes.MsgRoundChange { 114 if err != nil { 115 t.Errorf("error mismatch: have %v, want nil", err) 116 } 117 } else if testCode[i] == ibfttypes.MsgPreprepare { 118 if err != nil { 119 t.Errorf("error mismatch: have %v, want nil", err) 120 } 121 } else { 122 if err != istanbulcommon.ErrFutureMessage { 123 t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrFutureMessage) 124 } 125 } 126 } 127 128 // current view, state = StatePreprepared 129 c.state = ibfttypes.StatePreprepared 130 for i := 0; i < len(testCode); i++ { 131 err = c.checkMessage(testCode[i], v) 132 if testCode[i] == ibfttypes.MsgRoundChange { 133 if err != nil { 134 t.Errorf("error mismatch: have %v, want nil", err) 135 } 136 } else if err != nil { 137 t.Errorf("error mismatch: have %v, want nil", err) 138 } 139 } 140 141 // current view, state = ibfttypes.StatePrepared 142 c.state = ibfttypes.StatePrepared 143 for i := 0; i < len(testCode); i++ { 144 err = c.checkMessage(testCode[i], v) 145 if testCode[i] == ibfttypes.MsgRoundChange { 146 if err != nil { 147 t.Errorf("error mismatch: have %v, want nil", err) 148 } 149 } else if err != nil { 150 t.Errorf("error mismatch: have %v, want nil", err) 151 } 152 } 153 154 // current view, state = ibfttypes.StateCommitted 155 c.state = ibfttypes.StateCommitted 156 for i := 0; i < len(testCode); i++ { 157 err = c.checkMessage(testCode[i], v) 158 if testCode[i] == ibfttypes.MsgRoundChange { 159 if err != nil { 160 t.Errorf("error mismatch: have %v, want nil", err) 161 } 162 } else if err != nil { 163 t.Errorf("error mismatch: have %v, want nil", err) 164 } 165 } 166 167 } 168 169 func TestStoreBacklog(t *testing.T) { 170 c := &core{ 171 logger: log.New("backend", "test", "id", 0), 172 valSet: newTestValidatorSet(1), 173 backlogs: make(map[common.Address]*prque.Prque), 174 backlogsMu: new(sync.Mutex), 175 } 176 v := &istanbul.View{ 177 Round: big.NewInt(10), 178 Sequence: big.NewInt(10), 179 } 180 p := c.valSet.GetByIndex(0) 181 // push preprepare msg 182 preprepare := &istanbul.Preprepare{ 183 View: v, 184 Proposal: makeBlock(1), 185 } 186 prepreparePayload, _ := ibfttypes.Encode(preprepare) 187 m := &ibfttypes.Message{ 188 Code: ibfttypes.MsgPreprepare, 189 Msg: prepreparePayload, 190 } 191 c.storeBacklog(m, p) 192 msg := c.backlogs[p.Address()].PopItem() 193 if !reflect.DeepEqual(msg, m) { 194 t.Errorf("message mismatch: have %v, want %v", msg, m) 195 } 196 197 // push prepare msg 198 subject := &istanbul.Subject{ 199 View: v, 200 Digest: common.StringToHash("1234567890"), 201 } 202 subjectPayload, _ := ibfttypes.Encode(subject) 203 204 m = &ibfttypes.Message{ 205 Code: ibfttypes.MsgPrepare, 206 Msg: subjectPayload, 207 } 208 c.storeBacklog(m, p) 209 msg = c.backlogs[p.Address()].PopItem() 210 if !reflect.DeepEqual(msg, m) { 211 t.Errorf("message mismatch: have %v, want %v", msg, m) 212 } 213 214 // push commit msg 215 m = &ibfttypes.Message{ 216 Code: ibfttypes.MsgCommit, 217 Msg: subjectPayload, 218 } 219 c.storeBacklog(m, p) 220 msg = c.backlogs[p.Address()].PopItem() 221 if !reflect.DeepEqual(msg, m) { 222 t.Errorf("message mismatch: have %v, want %v", msg, m) 223 } 224 225 // push roundChange msg 226 m = &ibfttypes.Message{ 227 Code: ibfttypes.MsgRoundChange, 228 Msg: subjectPayload, 229 } 230 c.storeBacklog(m, p) 231 msg = c.backlogs[p.Address()].PopItem() 232 if !reflect.DeepEqual(msg, m) { 233 t.Errorf("message mismatch: have %v, want %v", msg, m) 234 } 235 } 236 237 func TestProcessFutureBacklog(t *testing.T) { 238 backend := &testSystemBackend{ 239 events: new(event.TypeMux), 240 } 241 c := &core{ 242 logger: log.New("backend", "test", "id", 0), 243 valSet: newTestValidatorSet(1), 244 backlogs: make(map[common.Address]*prque.Prque), 245 backlogsMu: new(sync.Mutex), 246 backend: backend, 247 current: newRoundState(&istanbul.View{ 248 Sequence: big.NewInt(1), 249 Round: big.NewInt(0), 250 }, newTestValidatorSet(4), common.Hash{}, nil, nil, nil), 251 state: ibfttypes.StateAcceptRequest, 252 } 253 c.subscribeEvents() 254 defer c.unsubscribeEvents() 255 256 v := &istanbul.View{ 257 Round: big.NewInt(10), 258 Sequence: big.NewInt(10), 259 } 260 p := c.valSet.GetByIndex(0) 261 // push a future msg 262 subject := &istanbul.Subject{ 263 View: v, 264 Digest: common.StringToHash("1234567890"), 265 } 266 subjectPayload, _ := ibfttypes.Encode(subject) 267 m := &ibfttypes.Message{ 268 Code: ibfttypes.MsgCommit, 269 Msg: subjectPayload, 270 } 271 c.storeBacklog(m, p) 272 c.processBacklog() 273 274 const timeoutDura = 2 * time.Second 275 timeout := time.NewTimer(timeoutDura) 276 select { 277 case e, ok := <-c.events.Chan(): 278 if !ok { 279 return 280 } 281 t.Errorf("unexpected events comes: %v", e) 282 case <-timeout.C: 283 // success 284 } 285 } 286 287 func TestProcessBacklog(t *testing.T) { 288 v := &istanbul.View{ 289 Round: big.NewInt(0), 290 Sequence: big.NewInt(1), 291 } 292 preprepare := &istanbul.Preprepare{ 293 View: v, 294 Proposal: makeBlock(1), 295 } 296 prepreparePayload, _ := ibfttypes.Encode(preprepare) 297 298 subject := &istanbul.Subject{ 299 View: v, 300 Digest: common.StringToHash("1234567890"), 301 } 302 subjectPayload, _ := ibfttypes.Encode(subject) 303 304 msgs := []*ibfttypes.Message{ 305 { 306 Code: ibfttypes.MsgPreprepare, 307 Msg: prepreparePayload, 308 }, 309 { 310 Code: ibfttypes.MsgPrepare, 311 Msg: subjectPayload, 312 }, 313 { 314 Code: ibfttypes.MsgCommit, 315 Msg: subjectPayload, 316 }, 317 { 318 Code: ibfttypes.MsgRoundChange, 319 Msg: subjectPayload, 320 }, 321 } 322 for i := 0; i < len(msgs); i++ { 323 testProcessBacklog(t, msgs[i]) 324 } 325 } 326 327 func testProcessBacklog(t *testing.T, msg *ibfttypes.Message) { 328 vset := newTestValidatorSet(1) 329 backend := &testSystemBackend{ 330 events: new(event.TypeMux), 331 peers: vset, 332 } 333 c := &core{ 334 logger: log.New("backend", "test", "id", 0), 335 backlogs: make(map[common.Address]*prque.Prque), 336 backlogsMu: new(sync.Mutex), 337 valSet: vset, 338 backend: backend, 339 state: ibfttypes.State(msg.Code), 340 current: newRoundState(&istanbul.View{ 341 Sequence: big.NewInt(1), 342 Round: big.NewInt(0), 343 }, newTestValidatorSet(4), common.Hash{}, nil, nil, nil), 344 } 345 c.subscribeEvents() 346 defer c.unsubscribeEvents() 347 348 c.storeBacklog(msg, vset.GetByIndex(0)) 349 c.processBacklog() 350 351 const timeoutDura = 2 * time.Second 352 timeout := time.NewTimer(timeoutDura) 353 select { 354 case ev := <-c.events.Chan(): 355 e, ok := ev.Data.(backlogEvent) 356 if !ok { 357 t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) 358 } 359 if e.msg.Code != msg.Code { 360 t.Errorf("message code mismatch: have %v, want %v", e.msg.Code, msg.Code) 361 } 362 // success 363 case <-timeout.C: 364 t.Error("unexpected timeout occurs") 365 } 366 }