github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/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 "fmt" 21 blscrypto "github.com/ethereum/go-ethereum/crypto/bls" 22 "math/big" 23 "reflect" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/consensus/istanbul" 29 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 30 "github.com/ethereum/go-ethereum/event" 31 elog "github.com/ethereum/go-ethereum/log" 32 ) 33 34 func TestCheckMessage(t *testing.T) { 35 testLogger.SetHandler(elog.StdoutHandler) 36 backend := &testSystemBackend{ 37 events: new(event.TypeMux), 38 } 39 valSet := newTestValidatorSet(4) 40 c := &core{ 41 logger: testLogger, 42 backend: backend, 43 current: newRoundState(&istanbul.View{ 44 Sequence: big.NewInt(2), 45 Round: big.NewInt(2), 46 }, valSet, valSet.GetByIndex(0)), 47 } 48 49 t.Run("invalid view format", func(t *testing.T) { 50 err := c.checkMessage(istanbul.MsgPreprepare, nil) 51 if err != errInvalidMessage { 52 t.Errorf("error mismatch: have %v, want %v", err, errInvalidMessage) 53 } 54 }) 55 56 testStates := []State{StateAcceptRequest, StatePreprepared, StatePrepared, StateCommitted, StateWaitingForNewRound} 57 testCodes := []uint64{istanbul.MsgPreprepare, istanbul.MsgPrepare, istanbul.MsgCommit, istanbul.MsgRoundChange} 58 59 // accept Commits from sequence, round matching LastSubject 60 t.Run("Rejects all other older rounds", func(t *testing.T) { 61 v := &istanbul.View{ 62 Sequence: big.NewInt(2), 63 Round: big.NewInt(1), 64 } 65 for _, testState := range testStates { 66 for _, testCode := range testCodes { 67 c.current.(*roundStateImpl).state = testState 68 err := c.checkMessage(testCode, v) 69 70 if err != errOldMessage { 71 t.Errorf("error mismatch: have %v, want %v", err, errOldMessage) 72 } 73 74 } 75 } 76 }) 77 78 t.Run("Rejects all other older sequences", func(t *testing.T) { 79 v := &istanbul.View{ 80 Sequence: big.NewInt(0), 81 Round: big.NewInt(0), 82 } 83 for _, testState := range testStates { 84 for _, testCode := range testCodes { 85 c.current.(*roundStateImpl).state = testState 86 err := c.checkMessage(testCode, v) 87 if err != errOldMessage { 88 t.Errorf("error mismatch: have %v, want %v", err, errOldMessage) 89 } 90 } 91 } 92 }) 93 94 t.Run("Future sequence", func(t *testing.T) { 95 v := &istanbul.View{ 96 Sequence: big.NewInt(3), 97 Round: big.NewInt(0), 98 } 99 for _, testState := range testStates { 100 for _, testCode := range testCodes { 101 c.current.(*roundStateImpl).state = testState 102 err := c.checkMessage(testCode, v) 103 if err != errFutureMessage { 104 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 105 } 106 } 107 } 108 }) 109 110 t.Run("future round", func(t *testing.T) { 111 v := &istanbul.View{ 112 Sequence: big.NewInt(2), 113 Round: big.NewInt(3), 114 } 115 for _, testState := range testStates { 116 for _, testCode := range testCodes { 117 c.current.(*roundStateImpl).state = testState 118 err := c.checkMessage(testCode, v) 119 if testCode == istanbul.MsgRoundChange { 120 if err != nil { 121 t.Errorf("error mismatch: have %v, want nil", err) 122 } 123 } else if err != errFutureMessage { 124 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 125 } 126 } 127 } 128 }) 129 130 t.Run("current view, state = StateAcceptRequest", func(t *testing.T) { 131 v := c.current.View() 132 c.current.(*roundStateImpl).state = StateAcceptRequest 133 134 for _, testCode := range testCodes { 135 err := c.checkMessage(testCode, v) 136 if testCode == istanbul.MsgRoundChange { 137 if err != nil { 138 t.Errorf("error mismatch: have %v, want nil", err) 139 } 140 } else if testCode == istanbul.MsgPreprepare { 141 if err != nil { 142 t.Errorf("error mismatch: have %v, want nil", err) 143 } 144 } else { 145 if err != errFutureMessage { 146 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 147 } 148 } 149 } 150 }) 151 152 t.Run("current view, state = StatePreprepared", func(t *testing.T) { 153 v := c.current.View() 154 c.current.(*roundStateImpl).state = StatePreprepared 155 for _, testCode := range testCodes { 156 err := c.checkMessage(testCode, v) 157 if testCode == istanbul.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 t.Run("current view, state = StatePrepared", func(t *testing.T) { 168 v := c.current.View() 169 c.current.(*roundStateImpl).state = StatePrepared 170 for _, testCode := range testCodes { 171 err := c.checkMessage(testCode, v) 172 if testCode == istanbul.MsgRoundChange { 173 if err != nil { 174 t.Errorf("error mismatch: have %v, want nil", err) 175 } 176 } else if err != nil { 177 t.Errorf("error mismatch: have %v, want nil", err) 178 } 179 } 180 }) 181 182 t.Run("current view, state = StateCommited", func(t *testing.T) { 183 v := c.current.View() 184 c.current.(*roundStateImpl).state = StateCommitted 185 for _, testCode := range testCodes { 186 err := c.checkMessage(testCode, v) 187 if testCode == istanbul.MsgRoundChange { 188 if err != nil { 189 t.Errorf("error mismatch: have %v, want nil", err) 190 } 191 } else if err != nil { 192 t.Errorf("error mismatch: have %v, want nil", err) 193 } 194 } 195 }) 196 197 t.Run("current view, state = StateWaitingForNewRound", func(t *testing.T) { 198 v := c.current.View() 199 c.current.(*roundStateImpl).state = StateWaitingForNewRound 200 for _, testCode := range testCodes { 201 err := c.checkMessage(testCode, v) 202 if testCode == istanbul.MsgRoundChange { 203 if err != nil { 204 t.Errorf("error mismatch: have %v, want nil", err) 205 } 206 } else if err != errFutureMessage { 207 t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage) 208 } 209 } 210 }) 211 212 } 213 214 func TestStoreBacklog(t *testing.T) { 215 testLogger.SetHandler(elog.StdoutHandler) 216 backlog := newMsgBacklog( 217 func(msg *istanbul.Message) {}, 218 func(msgCode uint64, msgView *istanbul.View) error { return nil }, 219 ).(*msgBacklogImpl) 220 221 v10 := &istanbul.View{ 222 Round: big.NewInt(10), 223 Sequence: big.NewInt(10), 224 } 225 226 v11 := &istanbul.View{ 227 Round: big.NewInt(12), 228 Sequence: big.NewInt(11), 229 } 230 p1 := validator.New(common.BytesToAddress([]byte("12345667890")), blscrypto.SerializedPublicKey{}) 231 p2 := validator.New(common.BytesToAddress([]byte("47324349949")), blscrypto.SerializedPublicKey{}) 232 233 // push messages 234 preprepare := &istanbul.Preprepare{ 235 View: v10, 236 Proposal: makeBlock(10), 237 } 238 239 prepreparePayload, _ := Encode(preprepare) 240 mPreprepare := &istanbul.Message{ 241 Code: istanbul.MsgPreprepare, 242 Msg: prepreparePayload, 243 Address: p1.Address(), 244 } 245 246 backlog.store(mPreprepare) 247 248 msg := backlog.backlogBySeq[v10.Sequence.Uint64()].PopItem() 249 if !reflect.DeepEqual(msg, mPreprepare) { 250 t.Errorf("message mismatch: have %v, want %v", msg, mPreprepare) 251 } 252 253 subject := &istanbul.Subject{ 254 View: v10, 255 Digest: common.BytesToHash([]byte("1234567890")), 256 } 257 subjectPayload, _ := Encode(subject) 258 mPrepare := &istanbul.Message{ 259 Code: istanbul.MsgPrepare, 260 Msg: subjectPayload, 261 Address: p1.Address(), 262 } 263 264 preprepare2 := &istanbul.Preprepare{ 265 View: v11, 266 Proposal: makeBlock(11), 267 } 268 preprepare2Payload, _ := Encode(preprepare2) 269 mPreprepare2 := &istanbul.Message{ 270 Code: istanbul.MsgPreprepare, 271 Msg: preprepare2Payload, 272 Address: p2.Address(), 273 } 274 275 backlog.store(mPreprepare) 276 backlog.store(mPrepare) 277 backlog.store(mPreprepare2) 278 279 if backlog.msgCountBySrc[p1.Address()] != 3 { 280 t.Errorf("msgCountBySrc mismatch: have %v, want 3", backlog.msgCountBySrc[p1.Address()]) 281 } 282 // push commit msg 283 committedSubject := &istanbul.CommittedSubject{ 284 Subject: subject, 285 CommittedSeal: []byte{0x63, 0x65, 0x6C, 0x6F}, // celo in hex! 286 } 287 288 committedSubjectPayload, _ := Encode(committedSubject) 289 290 mCommit := &istanbul.Message{ 291 Code: istanbul.MsgCommit, 292 Msg: committedSubjectPayload, 293 Address: p1.Address(), 294 } 295 296 backlog.store(mCommit) 297 if backlog.msgCountBySrc[p2.Address()] != 1 { 298 t.Errorf("msgCountBySrc mismatch: have %v, want 1", backlog.msgCountBySrc[p2.Address()]) 299 } 300 if backlog.msgCount != 5 { 301 t.Errorf("msgCount mismatch: have %v, want 5", backlog.msgCount) 302 } 303 304 // Should get back v10 preprepare then commit 305 msg = backlog.backlogBySeq[v10.Sequence.Uint64()].PopItem() 306 if !reflect.DeepEqual(msg, mPreprepare) { 307 t.Errorf("message mismatch: have %v, want %v", msg, mPreprepare2) 308 } 309 msg = backlog.backlogBySeq[v10.Sequence.Uint64()].PopItem() 310 if !reflect.DeepEqual(msg, mCommit) { 311 t.Errorf("message mismatch: have %v, want %v", msg, mCommit) 312 313 } 314 msg = backlog.backlogBySeq[v11.Sequence.Uint64()].PopItem() 315 if !reflect.DeepEqual(msg, mPreprepare2) { 316 t.Errorf("message mismatch: have %v, want %v", msg, mPreprepare2) 317 } 318 319 backlog.msgCount = 0 320 delete(backlog.msgCountBySrc, p1.Address()) 321 delete(backlog.msgCountBySrc, p2.Address()) 322 } 323 324 func TestProcessFutureBacklog(t *testing.T) { 325 testLogger.SetHandler(elog.StdoutHandler) 326 327 backlog := newMsgBacklog( 328 func(msg *istanbul.Message) {}, 329 func(msgCode uint64, msgView *istanbul.View) error { return nil }, 330 ).(*msgBacklogImpl) 331 332 // push a future msg 333 v := &istanbul.View{ 334 Round: big.NewInt(10), 335 Sequence: big.NewInt(10), 336 } 337 338 committedSubject := &istanbul.CommittedSubject{ 339 Subject: &istanbul.Subject{ 340 View: v, 341 Digest: common.BytesToHash([]byte("1234567890")), 342 }, 343 CommittedSeal: []byte{0x63, 0x65, 0x6C, 0x6F}, 344 } 345 346 committedSubjectPayload, _ := Encode(committedSubject) 347 // push a future msg 348 valSet := newTestValidatorSet(4) 349 mFuture := &istanbul.Message{ 350 Code: istanbul.MsgCommit, 351 Msg: committedSubjectPayload, 352 Address: valSet.GetByIndex(0).Address(), 353 } 354 backlog.store(mFuture) 355 356 // push a message from the past and check we expire it 357 v0 := &istanbul.View{ 358 Round: big.NewInt(0), 359 Sequence: big.NewInt(0), 360 } 361 subject0 := &istanbul.Subject{ 362 View: v0, 363 Digest: common.BytesToHash([]byte("1234567890")), 364 } 365 subjectPayload0, _ := Encode(subject0) 366 mPast := &istanbul.Message{ 367 Code: istanbul.MsgRoundChange, 368 Msg: subjectPayload0, 369 Address: valSet.GetByIndex(1).Address(), 370 } 371 backlog.store(mPast) 372 373 backlogSeqs := backlog.getSortedBacklogSeqs() 374 if len(backlogSeqs) != 1 || backlogSeqs[0] != v.Sequence.Uint64() { 375 t.Errorf("getSortedBacklogSeqs mismatch: have %v", backlogSeqs) 376 } 377 378 backlog.updateState(&istanbul.View{ 379 Sequence: big.NewInt(1), 380 Round: big.NewInt(0), 381 }, StateAcceptRequest) 382 383 // Check message from future remains, past expired 384 if backlog.msgCount != 1 || backlog.msgCountBySrc[valSet.GetByIndex(1).Address()] > 0 { 385 t.Errorf("backlog mismatch: %v", backlog.msgCountBySrc) 386 } 387 } 388 389 func TestProcessBacklog(t *testing.T) { 390 v := &istanbul.View{ 391 Round: big.NewInt(0), 392 Sequence: big.NewInt(1), 393 } 394 preprepare := &istanbul.Preprepare{ 395 View: v, 396 Proposal: makeBlock(1), 397 } 398 prepreparePayload, _ := Encode(preprepare) 399 400 subject := &istanbul.Subject{ 401 View: v, 402 Digest: common.BytesToHash([]byte("1234567890")), 403 } 404 subjectPayload, _ := Encode(subject) 405 406 committedSubject := &istanbul.CommittedSubject{ 407 Subject: subject, 408 CommittedSeal: []byte{0x63, 0x65, 0x6C, 0x6F}, 409 } 410 committedSubjectPayload, _ := Encode(committedSubject) 411 412 rc := &istanbul.RoundChange{ 413 View: v, 414 PreparedCertificate: istanbul.EmptyPreparedCertificate(), 415 } 416 rcPayload, _ := Encode(rc) 417 418 address := common.BytesToAddress([]byte("0xce10ce10")) 419 420 msgs := []*istanbul.Message{ 421 { 422 Code: istanbul.MsgPreprepare, 423 Msg: prepreparePayload, 424 Address: address, 425 }, 426 { 427 Code: istanbul.MsgPrepare, 428 Msg: subjectPayload, 429 Address: address, 430 }, 431 { 432 Code: istanbul.MsgCommit, 433 Msg: committedSubjectPayload, 434 Address: address, 435 }, 436 { 437 Code: istanbul.MsgRoundChange, 438 Msg: rcPayload, 439 Address: address, 440 }, 441 } 442 for i := 0; i < len(msgs); i++ { 443 t.Run(fmt.Sprintf("Msg with code %d", msgs[i].Code), func(t *testing.T) { 444 testProcessBacklog(t, msgs[i]) 445 }) 446 } 447 } 448 449 func testProcessBacklog(t *testing.T, msg *istanbul.Message) { 450 451 testLogger.SetHandler(elog.StdoutHandler) 452 453 processedMsgs := make(chan uint64, 100) 454 registerCall := func(msg *istanbul.Message) { 455 processedMsgs <- msg.Code 456 // we expect only one msg 457 close(processedMsgs) 458 } 459 460 backlog := newMsgBacklog( 461 registerCall, 462 func(msgCode uint64, msgView *istanbul.View) error { return nil }, 463 ).(*msgBacklogImpl) 464 465 v := &istanbul.View{ 466 Round: big.NewInt(0), 467 Sequence: big.NewInt(1), 468 } 469 470 msg.Address = common.Address{50} 471 backlog.store(msg) 472 473 backlog.updateState(v, State(msg.Code)) 474 475 timeout := time.NewTimer(1 * time.Second) 476 477 select { 478 case got := <-processedMsgs: 479 if got != msg.Code { 480 t.Errorf("Expected different msg: have: %v, want: %v", got, msg.Code) 481 } 482 case <-timeout.C: 483 t.Errorf("No Message was processed") 484 } 485 486 }