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