github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/backlog_test.go (about) 1 package core 2 3 import ( 4 "math/big" 5 "reflect" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/quickchainproject/quickchain/common" 11 "github.com/quickchainproject/quickchain/consensus/dbft" 12 "github.com/quickchainproject/quickchain/consensus/dbft/validator" 13 "github.com/quickchainproject/quickchain/event" 14 "github.com/quickchainproject/quickchain/log" 15 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 16 ) 17 18 func TestCheckMessage(t *testing.T) { 19 c := &core{ 20 state: StateAcceptRequest, 21 current: newRoundState(&bft.View{ 22 Sequence: big.NewInt(1), 23 Round: big.NewInt(0), 24 }, newTestValidatorSet(4), common.Hash{}, nil, nil, nil), 25 } 26 27 // invalid view format 28 err := c.checkMessage(msgPreprepare, nil) 29 if err != errInvalidMessage { 30 t.Errorf("error mismatch: have %v, want %v", err, errInvalidMessage) 31 } 32 33 testStates := []State{StateAcceptRequest, StatePreprepared, StatePrepared, StateCommitted} 34 testCode := []uint64{msgPreprepare, msgPrepare, msgCommit, msgRoundChange} 35 36 // future sequence 37 v := &bft.View{ 38 Sequence: big.NewInt(2), 39 Round: big.NewInt(0), 40 } 41 for i := 0; i < len(testStates); i++ { 42 c.state = testStates[i] 43 for j := 0; j < len(testCode); j++ { 44 err := c.checkMessage(testCode[j], v) 45 if err != errFutureMessage { 46 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 47 } 48 } 49 } 50 51 // future round 52 v = &bft.View{ 53 Sequence: big.NewInt(1), 54 Round: big.NewInt(1), 55 } 56 for i := 0; i < len(testStates); i++ { 57 c.state = testStates[i] 58 for j := 0; j < len(testCode); j++ { 59 err := c.checkMessage(testCode[j], v) 60 if testCode[j] == msgRoundChange { 61 if err != nil { 62 t.Errorf("error mismatch: have %v, want nil", err) 63 } 64 } else if err != errFutureMessage { 65 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 66 } 67 } 68 } 69 70 // current view but waiting for round change 71 v = &bft.View{ 72 Sequence: big.NewInt(1), 73 Round: big.NewInt(0), 74 } 75 c.waitingForRoundChange = true 76 for i := 0; i < len(testStates); i++ { 77 c.state = testStates[i] 78 for j := 0; j < len(testCode); j++ { 79 err := c.checkMessage(testCode[j], v) 80 if testCode[j] == msgRoundChange { 81 if err != nil { 82 t.Errorf("error mismatch: have %v, want nil", err) 83 } 84 } else if err != errFutureMessage { 85 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 86 } 87 } 88 } 89 c.waitingForRoundChange = false 90 91 v = c.currentView() 92 // current view, state = StateAcceptRequest 93 c.state = StateAcceptRequest 94 for i := 0; i < len(testCode); i++ { 95 err = c.checkMessage(testCode[i], v) 96 if testCode[i] == msgRoundChange { 97 if err != nil { 98 t.Errorf("error mismatch: have %v, want nil", err) 99 } 100 } else if testCode[i] == msgPreprepare { 101 if err != nil { 102 t.Errorf("error mismatch: have %v, want nil", err) 103 } 104 } else { 105 if err != errFutureMessage { 106 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 107 } 108 } 109 } 110 111 // current view, state = StatePreprepared 112 c.state = StatePreprepared 113 for i := 0; i < len(testCode); i++ { 114 err = c.checkMessage(testCode[i], v) 115 if testCode[i] == msgRoundChange { 116 if err != nil { 117 t.Errorf("error mismatch: have %v, want nil", err) 118 } 119 } else if err != nil { 120 t.Errorf("error mismatch: have %v, want nil", err) 121 } 122 } 123 124 // current view, state = StatePrepared 125 c.state = StatePrepared 126 for i := 0; i < len(testCode); i++ { 127 err = c.checkMessage(testCode[i], v) 128 if testCode[i] == msgRoundChange { 129 if err != nil { 130 t.Errorf("error mismatch: have %v, want nil", err) 131 } 132 } else if err != nil { 133 t.Errorf("error mismatch: have %v, want nil", err) 134 } 135 } 136 137 // current view, state = StateCommitted 138 c.state = StateCommitted 139 for i := 0; i < len(testCode); i++ { 140 err = c.checkMessage(testCode[i], v) 141 if testCode[i] == msgRoundChange { 142 if err != nil { 143 t.Errorf("error mismatch: have %v, want nil", err) 144 } 145 } else if err != nil { 146 t.Errorf("error mismatch: have %v, want nil", err) 147 } 148 } 149 150 } 151 152 func TestStoreBacklog(t *testing.T) { 153 c := &core{ 154 logger: log.New("backend", "test", "id", 0), 155 backlogs: make(map[bft.Validator]*prque.Prque), 156 backlogsMu: new(sync.Mutex), 157 } 158 v := &bft.View{ 159 Round: big.NewInt(10), 160 Sequence: big.NewInt(10), 161 } 162 p := validator.New(common.StringToAddress("12345667890")) 163 // push preprepare msg 164 preprepare := &bft.Preprepare{ 165 View: v, 166 Proposal: makeBlock(1), 167 } 168 prepreparePayload, _ := Encode(preprepare) 169 m := &message{ 170 Code: msgPreprepare, 171 Msg: prepreparePayload, 172 } 173 c.storeBacklog(m, p) 174 msg := c.backlogs[p].PopItem() 175 if !reflect.DeepEqual(msg, m) { 176 t.Errorf("message mismatch: have %v, want %v", msg, m) 177 } 178 179 // push prepare msg 180 subject := &bft.Subject{ 181 View: v, 182 Digest: common.StringToHash("1234567890"), 183 } 184 subjectPayload, _ := Encode(subject) 185 186 m = &message{ 187 Code: msgPrepare, 188 Msg: subjectPayload, 189 } 190 c.storeBacklog(m, p) 191 msg = c.backlogs[p].PopItem() 192 if !reflect.DeepEqual(msg, m) { 193 t.Errorf("message mismatch: have %v, want %v", msg, m) 194 } 195 196 // push commit msg 197 m = &message{ 198 Code: msgCommit, 199 Msg: subjectPayload, 200 } 201 c.storeBacklog(m, p) 202 msg = c.backlogs[p].PopItem() 203 if !reflect.DeepEqual(msg, m) { 204 t.Errorf("message mismatch: have %v, want %v", msg, m) 205 } 206 207 // push roundChange msg 208 m = &message{ 209 Code: msgRoundChange, 210 Msg: subjectPayload, 211 } 212 c.storeBacklog(m, p) 213 msg = c.backlogs[p].PopItem() 214 if !reflect.DeepEqual(msg, m) { 215 t.Errorf("message mismatch: have %v, want %v", msg, m) 216 } 217 } 218 219 func TestProcessFutureBacklog(t *testing.T) { 220 backend := &testSystemBackend{ 221 events: new(event.TypeMux), 222 } 223 c := &core{ 224 logger: log.New("backend", "test", "id", 0), 225 backlogs: make(map[bft.Validator]*prque.Prque), 226 backlogsMu: new(sync.Mutex), 227 backend: backend, 228 current: newRoundState(&bft.View{ 229 Sequence: big.NewInt(1), 230 Round: big.NewInt(0), 231 }, newTestValidatorSet(4), common.Hash{}, nil, nil, nil), 232 state: StateAcceptRequest, 233 } 234 c.subscribeEvents() 235 defer c.unsubscribeEvents() 236 237 v := &bft.View{ 238 Round: big.NewInt(10), 239 Sequence: big.NewInt(10), 240 } 241 p := validator.New(common.StringToAddress("12345667890")) 242 // push a future msg 243 subject := &bft.Subject{ 244 View: v, 245 Digest: common.StringToHash("1234567890"), 246 } 247 subjectPayload, _ := Encode(subject) 248 m := &message{ 249 Code: msgCommit, 250 Msg: subjectPayload, 251 } 252 c.storeBacklog(m, p) 253 c.processBacklog() 254 255 const timeoutDura = 2 * time.Second 256 timeout := time.NewTimer(timeoutDura) 257 select { 258 case e, ok := <-c.events.Chan(): 259 if !ok { 260 return 261 } 262 t.Errorf("unexpected events comes: %v", e) 263 case <-timeout.C: 264 // success 265 } 266 } 267 268 func TestProcessBacklog(t *testing.T) { 269 v := &bft.View{ 270 Round: big.NewInt(0), 271 Sequence: big.NewInt(1), 272 } 273 preprepare := &bft.Preprepare{ 274 View: v, 275 Proposal: makeBlock(1), 276 } 277 prepreparePayload, _ := Encode(preprepare) 278 279 subject := &bft.Subject{ 280 View: v, 281 Digest: common.StringToHash("1234567890"), 282 } 283 subjectPayload, _ := Encode(subject) 284 285 msgs := []*message{ 286 &message{ 287 Code: msgPreprepare, 288 Msg: prepreparePayload, 289 }, 290 &message{ 291 Code: msgPrepare, 292 Msg: subjectPayload, 293 }, 294 &message{ 295 Code: msgCommit, 296 Msg: subjectPayload, 297 }, 298 &message{ 299 Code: msgRoundChange, 300 Msg: subjectPayload, 301 }, 302 } 303 for i := 0; i < len(msgs); i++ { 304 testProcessBacklog(t, msgs[i]) 305 } 306 } 307 308 func testProcessBacklog(t *testing.T, msg *message) { 309 vset := newTestValidatorSet(1) 310 backend := &testSystemBackend{ 311 events: new(event.TypeMux), 312 peers: vset, 313 } 314 c := &core{ 315 logger: log.New("backend", "test", "id", 0), 316 backlogs: make(map[bft.Validator]*prque.Prque), 317 backlogsMu: new(sync.Mutex), 318 backend: backend, 319 state: State(msg.Code), 320 current: newRoundState(&bft.View{ 321 Sequence: big.NewInt(1), 322 Round: big.NewInt(0), 323 }, newTestValidatorSet(4), common.Hash{}, nil, nil, nil), 324 } 325 c.subscribeEvents() 326 defer c.unsubscribeEvents() 327 328 c.storeBacklog(msg, vset.GetByIndex(0)) 329 c.processBacklog() 330 331 const timeoutDura = 2 * time.Second 332 timeout := time.NewTimer(timeoutDura) 333 select { 334 case ev := <-c.events.Chan(): 335 e, ok := ev.Data.(backlogEvent) 336 if !ok { 337 t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) 338 } 339 if e.msg.Code != msg.Code { 340 t.Errorf("message code mismatch: have %v, want %v", e.msg.Code, msg.Code) 341 } 342 // success 343 case <-timeout.C: 344 t.Error("unexpected timeout occurs") 345 } 346 }