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