github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/forks/test/finalizer_test.go (about) 1 package test 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/mock" 9 "github.com/stretchr/testify/require" 10 11 "github.com/koko1123/flow-go-1/consensus/hotstuff/forks" 12 "github.com/koko1123/flow-go-1/consensus/hotstuff/forks/finalizer" 13 "github.com/koko1123/flow-go-1/consensus/hotstuff/mocks" 14 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 15 mockm "github.com/koko1123/flow-go-1/module/mock" 16 ) 17 18 // denotion: 19 // A block is denoted as [<qc_number>, <block_view_number>]. 20 // For example, [1,2] means: a block of view 2 has a QC for view 1. 21 22 // receives [1,2], [2,3], [3,4], [4,5], 23 // it should finalize [1,2], it should lock [2,3]. 24 func TestLocked(t *testing.T) { 25 builder := NewBlockBuilder() 26 builder.Add(1, 2) // creates a block of view 2, with a QC of view 1 27 builder.Add(2, 3) 28 builder.Add(3, 4) 29 builder.Add(4, 5) 30 31 blocks, err := builder.Blocks() 32 require.Nil(t, err) 33 34 fin, _, _ := newFinalizer(t) 35 36 err = addBlocksToFinalizer(fin, blocks) 37 require.Nil(t, err) 38 39 assertFinalizedBlock(t, fin, 1, 2) // check if the finalized block has view 1, and its QC is 2 40 assertTheLockedBlock(t, fin, 2, 3) 41 // ^^^ the reason it's not called "assertLockedBlock" is to match 42 // its length with assertFinalizedBlock in order to align their arguments 43 } 44 45 // receives [1,2], [2,3], [3,4], [4,5], [4,6], [6,8] 46 // it should finalize [1,2], it should lock [3,4]. 47 func TestLocked2(t *testing.T) { 48 builder := NewBlockBuilder() 49 builder.Add(1, 2) 50 builder.Add(2, 3) 51 builder.Add(3, 4) 52 builder.Add(4, 5) 53 builder.Add(4, 6) 54 builder.Add(6, 8) 55 56 blocks, err := builder.Blocks() 57 require.Nil(t, err) 58 59 fin, _, _ := newFinalizer(t) 60 61 err = addBlocksToFinalizer(fin, blocks) 62 require.Nil(t, err) 63 64 assertFinalizedBlock(t, fin, 1, 2) 65 assertTheLockedBlock(t, fin, 3, 4) 66 } 67 68 // receives [1,2], [2,3], [3,4], [4,5], [4,6], [6,8], [8,10] 69 // it should finalize [1,2], it should lock [4,6]. 70 func TestLocked3(t *testing.T) { 71 builder := NewBlockBuilder() 72 builder.Add(1, 2) 73 builder.Add(2, 3) 74 builder.Add(3, 4) 75 builder.Add(4, 5) 76 builder.Add(4, 6) 77 builder.Add(6, 8) 78 builder.Add(8, 10) 79 80 blocks, err := builder.Blocks() 81 require.Nil(t, err) 82 83 fin, _, _ := newFinalizer(t) 84 85 err = addBlocksToFinalizer(fin, blocks) 86 require.Nil(t, err) 87 88 assertFinalizedBlock(t, fin, 1, 2) 89 assertTheLockedBlock(t, fin, 4, 6) 90 } 91 92 // receives [1,2], [2,3], [3,4], [4,5], [5,6] 93 // it should finalize [2,3], it should lock [3,4] 94 func TestFinalizedDirect3builder(t *testing.T) { 95 builder := NewBlockBuilder() 96 builder.Add(1, 2) 97 builder.Add(2, 3) 98 builder.Add(3, 4) 99 builder.Add(4, 5) 100 builder.Add(5, 6) 101 102 blocks, err := builder.Blocks() 103 require.Nil(t, err) 104 105 fin, _, _ := newFinalizer(t) 106 107 err = addBlocksToFinalizer(fin, blocks) 108 require.Nil(t, err) 109 110 assertFinalizedBlock(t, fin, 2, 3) 111 assertTheLockedBlock(t, fin, 3, 4) 112 } 113 114 // receives [1,2], [2,3], [3,4], [4,5], [5,6], [6,7], [7,8], [8, 9] 115 // it should finalize [5,6], it should lock [6,7] 116 func TestFinalizedDirect3builder2(t *testing.T) { 117 builder := NewBlockBuilder() 118 builder.Add(1, 2) 119 builder.Add(2, 3) 120 builder.Add(3, 4) 121 builder.Add(4, 5) 122 builder.Add(5, 6) 123 builder.Add(6, 7) 124 builder.Add(7, 8) 125 builder.Add(8, 9) 126 127 blocks, err := builder.Blocks() 128 require.Nil(t, err) 129 130 fin, _, _ := newFinalizer(t) 131 132 err = addBlocksToFinalizer(fin, blocks) 133 require.Nil(t, err) 134 135 assertFinalizedBlock(t, fin, 5, 6) 136 assertTheLockedBlock(t, fin, 6, 7) 137 } 138 139 // receives [1,2], [2,3], [3,4], [4,5], [5,7], 140 // it should finalize [2,3], it should lock [3,4] 141 func TestFinalizedDirect2builderPlus1builder(t *testing.T) { 142 builder := NewBlockBuilder() 143 builder.Add(1, 2) 144 builder.Add(2, 3) 145 builder.Add(3, 4) 146 builder.Add(4, 5) 147 builder.Add(5, 7) 148 149 blocks, err := builder.Blocks() 150 require.Nil(t, err) 151 152 fin, _, _ := newFinalizer(t) 153 154 err = addBlocksToFinalizer(fin, blocks) 155 require.Nil(t, err) 156 157 assertFinalizedBlock(t, fin, 2, 3) 158 assertTheLockedBlock(t, fin, 3, 4) 159 } 160 161 // receives [1,2], [2,3], [3,4], [4,5], [4,6], 162 // it should finalize [1,2], it should lock [2,3] 163 func TestUnfinalized(t *testing.T) { 164 builder := NewBlockBuilder() 165 builder.Add(1, 2) 166 builder.Add(2, 3) 167 builder.Add(3, 4) 168 builder.Add(4, 5) 169 builder.Add(4, 6) 170 171 blocks, err := builder.Blocks() 172 require.Nil(t, err) 173 174 fin, _, _ := newFinalizer(t) 175 176 err = addBlocksToFinalizer(fin, blocks) 177 require.Nil(t, err) 178 179 assertFinalizedBlock(t, fin, 1, 2) 180 assertTheLockedBlock(t, fin, 2, 3) 181 } 182 183 // receives [1,2], [2,3], [3,4], [4,5], [4,7], 184 // it should finalize [1,2], it should lock [2,3] 185 func TestUnfinalized2(t *testing.T) { 186 builder := NewBlockBuilder() 187 builder.Add(1, 2) 188 builder.Add(2, 3) 189 builder.Add(3, 4) 190 builder.Add(4, 5) 191 builder.Add(4, 7) 192 193 blocks, err := builder.Blocks() 194 require.Nil(t, err) 195 196 fin, _, _ := newFinalizer(t) 197 198 err = addBlocksToFinalizer(fin, blocks) 199 require.Nil(t, err) 200 201 assertFinalizedBlock(t, fin, 1, 2) 202 assertTheLockedBlock(t, fin, 2, 3) 203 } 204 205 // Tolerable Forks that extend from locked block (1: might change locked block, 2: not change locked block) 206 // receives [1,2], [2,3], [3,4], [4,5], [3,6], [6,7], [7,8] 207 // it should finalize [1,2], it should lock [3,6] 208 func TestTolerableForksExtendsFromLockedBlock(t *testing.T) { 209 builder := NewBlockBuilder() 210 builder.Add(1, 2) 211 builder.Add(2, 3) 212 builder.Add(3, 4) 213 builder.Add(4, 5) 214 builder.Add(3, 6) 215 builder.Add(6, 7) 216 builder.Add(7, 8) 217 218 blocks, err := builder.Blocks() 219 require.Nil(t, err) 220 221 fin, _, _ := newFinalizer(t) 222 223 err = addBlocksToFinalizer(fin, blocks) 224 require.Nil(t, err) 225 226 assertFinalizedBlock(t, fin, 1, 2) 227 assertTheLockedBlock(t, fin, 3, 6) 228 } 229 230 // receives [1,2], [2,3], [3,4], [4,5], [4,6], [6,7], [7,8] 231 // it should finalize [1,2], it should lock [4,6] 232 func TestTolerableForksExtendsFromLockedBlock2(t *testing.T) { 233 builder := NewBlockBuilder() 234 builder.Add(1, 2) 235 builder.Add(2, 3) 236 builder.Add(3, 4) 237 builder.Add(4, 5) 238 builder.Add(4, 6) 239 builder.Add(6, 7) 240 builder.Add(7, 8) 241 242 blocks, err := builder.Blocks() 243 require.Nil(t, err) 244 245 fin, _, _ := newFinalizer(t) 246 247 err = addBlocksToFinalizer(fin, blocks) 248 require.Nil(t, err) 249 250 assertFinalizedBlock(t, fin, 1, 2) 251 assertTheLockedBlock(t, fin, 4, 6) 252 } 253 254 // receives [1,2], [2,3], [3,4], [4,5], [3,6], [6,7], [7,8], [8,9] 255 // it should finalize [3,6], it should lock [6,7] 256 func TestTolerableForksExtendsFromLockedBlock3(t *testing.T) { 257 builder := NewBlockBuilder() 258 builder.Add(1, 2) 259 builder.Add(2, 3) 260 builder.Add(3, 4) 261 builder.Add(4, 5) 262 builder.Add(3, 6) 263 builder.Add(6, 7) 264 builder.Add(7, 8) 265 builder.Add(8, 9) 266 267 blocks, err := builder.Blocks() 268 require.Nil(t, err) 269 270 fin, _, _ := newFinalizer(t) 271 272 err = addBlocksToFinalizer(fin, blocks) 273 require.Nil(t, err) 274 275 assertFinalizedBlock(t, fin, 3, 6) 276 assertTheLockedBlock(t, fin, 6, 7) 277 } 278 279 // receives [1,2], [2,3], [3,4], [4,5], [4,6], [6,7], [7,8], [8,9] 280 // it should finalize [4,6], it should lock [6,7] 281 func TestTolerableForksExtendsFromLockedBlock4(t *testing.T) { 282 builder := NewBlockBuilder() 283 builder.Add(1, 2) 284 builder.Add(2, 3) 285 builder.Add(3, 4) 286 builder.Add(4, 5) 287 builder.Add(4, 6) 288 builder.Add(6, 7) 289 builder.Add(7, 8) 290 builder.Add(8, 9) 291 292 blocks, err := builder.Blocks() 293 require.Nil(t, err) 294 295 fin, _, _ := newFinalizer(t) 296 297 err = addBlocksToFinalizer(fin, blocks) 298 require.Nil(t, err) 299 300 assertFinalizedBlock(t, fin, 4, 6) 301 assertTheLockedBlock(t, fin, 6, 7) 302 } 303 304 // receives [1,2], [2,3], [3,4], [4,5], [4,6], [6,7], [7,8], [8,10] 305 // it should finalize [3,6], it should lock [6,7] 306 func TestTolerableForksExtendsFromLockedBlock5(t *testing.T) { 307 builder := NewBlockBuilder() 308 builder.Add(1, 2) 309 builder.Add(2, 3) 310 builder.Add(3, 4) 311 builder.Add(4, 5) 312 builder.Add(3, 6) 313 builder.Add(6, 7) 314 builder.Add(7, 8) 315 builder.Add(8, 10) 316 317 blocks, err := builder.Blocks() 318 require.Nil(t, err) 319 320 fin, _, _ := newFinalizer(t) 321 322 err = addBlocksToFinalizer(fin, blocks) 323 require.Nil(t, err) 324 325 assertFinalizedBlock(t, fin, 3, 6) 326 assertTheLockedBlock(t, fin, 6, 7) 327 } 328 329 // receives [1,2], [2,3], [3,4], [4,5], [2,6] 330 // it should finalize [1,2], it should lock [2,3] 331 func TestTolerableForksNotExtendsFromLockedBlock(t *testing.T) { 332 builder := NewBlockBuilder() 333 builder.Add(1, 2) 334 builder.Add(2, 3) 335 builder.Add(3, 4) 336 builder.Add(4, 5) 337 builder.Add(2, 6) 338 339 blocks, err := builder.Blocks() 340 require.Nil(t, err) 341 342 fin, _, _ := newFinalizer(t) 343 344 err = addBlocksToFinalizer(fin, blocks) 345 require.Nil(t, err) 346 347 assertFinalizedBlock(t, fin, 1, 2) 348 assertTheLockedBlock(t, fin, 2, 3) 349 } 350 351 // receives [1,2], [2,3], [3,4], [4,5], [2,6], [5,6] 352 // it should finalize [2,3], it should lock [3,4], because [2,6] is replaced by [5,6] 353 func TestTolerableForksNotExtendsFromLockedBlock2(t *testing.T) { 354 builder := NewBlockBuilder() 355 builder.Add(1, 2) 356 builder.Add(2, 3) 357 builder.Add(3, 4) 358 builder.Add(4, 5) 359 builder.Add(2, 6) 360 builder.Add(5, 6) 361 362 blocks, err := builder.Blocks() 363 require.Nil(t, err) 364 365 fin, notifier, _ := newFinalizer(t) 366 notifier.On("OnDoubleProposeDetected", blocks[5], blocks[4]).Return(nil) 367 368 err = addBlocksToFinalizer(fin, blocks) 369 require.Nil(t, err) 370 371 assertFinalizedBlock(t, fin, 2, 3) 372 assertTheLockedBlock(t, fin, 3, 4) 373 notifier.AssertExpectations(t) 374 } 375 376 // receives [1,2], [2,3], [3,4], [4,5], [2,6], [6,7] 377 // it should finalize [1,2], it should lock [2,3] 378 func TestTolerableForksNotExtendsFromLockedBlock3(t *testing.T) { 379 builder := NewBlockBuilder() 380 builder.Add(1, 2) 381 builder.Add(2, 3) 382 builder.Add(3, 4) 383 builder.Add(4, 5) 384 builder.Add(2, 6) 385 builder.Add(6, 7) 386 387 blocks, err := builder.Blocks() 388 require.Nil(t, err) 389 390 fin, _, _ := newFinalizer(t) 391 392 err = addBlocksToFinalizer(fin, blocks) 393 require.Nil(t, err) 394 395 assertFinalizedBlock(t, fin, 1, 2) 396 assertTheLockedBlock(t, fin, 2, 3) 397 } 398 399 // receives [1,2], [2,3], [3,4], [4,5], [2,6], [6,7],[7,8] 400 // it should finalize [1,2], it should lock [2,6] 401 func TestTolerableForksNotExtendsFromLockedBlock4(t *testing.T) { 402 builder := NewBlockBuilder() 403 builder.Add(1, 2) 404 builder.Add(2, 3) 405 builder.Add(3, 4) 406 builder.Add(4, 5) 407 builder.Add(2, 6) 408 builder.Add(6, 7) 409 builder.Add(7, 8) 410 411 blocks, err := builder.Blocks() 412 require.Nil(t, err) 413 414 fin, _, _ := newFinalizer(t) 415 416 err = addBlocksToFinalizer(fin, blocks) 417 require.Nil(t, err) 418 419 assertFinalizedBlock(t, fin, 1, 2) 420 assertTheLockedBlock(t, fin, 2, 6) 421 } 422 423 // receives [1,2], [2,3], [2,3], [3,4], [3,4], [4,5], [4,5], [5,6], [5,6] 424 // it should finalize [2,3], it should lock [3,4] 425 func TestDuplication(t *testing.T) { 426 builder := NewBlockBuilder() 427 builder.Add(1, 2) 428 builder.Add(2, 3) 429 builder.Add(3, 4) 430 builder.Add(2, 3) 431 builder.Add(3, 4) 432 builder.Add(4, 5) 433 builder.Add(5, 6) 434 builder.Add(4, 5) 435 builder.Add(5, 6) 436 437 blocks, err := builder.Blocks() 438 require.Nil(t, err) 439 440 fin, _, _ := newFinalizer(t) 441 442 err = addBlocksToFinalizer(fin, blocks) 443 require.Nil(t, err) 444 445 assertFinalizedBlock(t, fin, 2, 3) 446 assertTheLockedBlock(t, fin, 3, 4) 447 } 448 449 // receives [1,2], [2,3], [3,4], [4,5], [1,6] 450 // it should finalize [1,2], it should lock [2,3] 451 func TestIgnoreBlocksBelowFinalizedView(t *testing.T) { 452 builder := NewBlockBuilder() 453 builder.Add(1, 2) 454 builder.Add(2, 3) 455 builder.Add(3, 4) 456 builder.Add(4, 5) 457 builder.Add(1, 6) 458 459 blocks, err := builder.Blocks() 460 require.Nil(t, err) 461 462 fin, _, _ := newFinalizer(t) 463 464 err = addBlocksToFinalizer(fin, blocks) 465 require.Nil(t, err) 466 467 assertFinalizedBlock(t, fin, 1, 2) 468 assertTheLockedBlock(t, fin, 2, 3) 469 } 470 471 // receives [1,2], [2,3], [3,4], [4,5], [3,6], [5,6']. 472 // it should finalize block [2,3], and emits an DoubleProposal event with ([3,6], [5,6']) 473 func TestDoubleProposal(t *testing.T) { 474 builder := NewBlockBuilder() 475 builder.Add(1, 2) 476 builder.Add(2, 3) 477 builder.Add(3, 4) 478 builder.Add(4, 5) 479 builder.Add(3, 6) 480 builder.AddVersioned(5, 6, 0, 1) 481 482 blocks, err := builder.Blocks() 483 require.Nil(t, err) 484 485 fin, notifier, _ := newFinalizer(t) 486 notifier.On("OnDoubleProposeDetected", blocks[5], blocks[4]).Return(nil) 487 488 err = addBlocksToFinalizer(fin, blocks) 489 require.Nil(t, err) 490 491 assertFinalizedBlock(t, fin, 2, 3) 492 notifier.AssertExpectations(t) 493 } 494 495 // receives [1,2], [2,3], [3,4], [3,4'], [4,5], [4',6]. 496 // it should return fatal error, because conflicting blocks 4 and 4' 497 // both received enough votes for QC 498 func TestUntolerableForks(t *testing.T) { 499 builder := NewBlockBuilder() 500 501 builder.Add(1, 2) 502 builder.Add(2, 3) 503 builder.Add(3, 4) 504 builder.AddVersioned(3, 4, 0, 1) // make a special view 4 505 builder.Add(4, 5) 506 builder.AddVersioned(4, 6, 1, 0) // make a special view 6 extends from special view 4 507 508 blocks, err := builder.Blocks() 509 require.Nil(t, err) 510 511 fin, notifier, _ := newFinalizer(t) 512 notifier.On("OnDoubleProposeDetected", blocks[3], blocks[2]).Return(nil) 513 514 err = addBlocksToFinalizer(fin, blocks) 515 require.NotNil(t, err) 516 notifier.AssertExpectations(t) 517 } 518 519 // receives [1,2], [2,3], [2,7], [3,4], [4,5], [5,6], [7,8], [8,9], [9,10] 520 // It should return fatal error, because a fork below locked block got finalized 521 func TestUntolerableForks2(t *testing.T) { 522 builder := NewBlockBuilder() 523 builder.Add(1, 2) 524 builder.Add(2, 3) 525 builder.Add(3, 4) 526 builder.Add(4, 5) 527 builder.Add(5, 6) // this finalizes (2,3) 528 builder.Add(2, 7) 529 builder.Add(7, 8) 530 builder.Add(8, 9) 531 builder.Add(9, 10) // this finalizes (2,7), which is a conflicting fork with (2,3) 532 533 blocks, err := builder.Blocks() 534 require.Nil(t, err) 535 536 fin, _, _ := newFinalizer(t) 537 538 err = addBlocksToFinalizer(fin, blocks) 539 assert.Error(t, err) 540 } 541 542 func TestNotification(t *testing.T) { 543 builder := NewBlockBuilder() 544 builder.Add(1, 2) 545 builder.Add(2, 3) 546 builder.Add(3, 4) 547 builder.Add(4, 5) 548 549 blocks, err := builder.Blocks() 550 require.Nil(t, err) 551 552 notifier := &mocks.Consumer{} 553 // 5 blocks including the genesis are incorporated 554 notifier.On("OnBlockIncorporated", mock.Anything).Return(nil).Times(5) 555 notifier.On("OnFinalizedBlock", blocks[0]).Return(nil).Once() 556 finalizationCallback := &mockm.Finalizer{} 557 finalizationCallback.On("MakeFinal", blocks[0].BlockID).Return(nil).Once() 558 finalizationCallback.On("MakeValid", mock.Anything).Return(nil) 559 560 genesisBQ := makeGenesis() 561 562 fin, err := finalizer.New(genesisBQ, finalizationCallback, notifier) 563 require.NoError(t, err) 564 565 err = addBlocksToFinalizer(fin, blocks) 566 require.NoError(t, err) 567 notifier.AssertExpectations(t) 568 finalizationCallback.AssertExpectations(t) 569 } 570 571 // ========== internal functions =============== 572 573 func newFinalizer(t *testing.T) (forks.Finalizer, *mocks.Consumer, *mockm.Finalizer) { 574 notifier := &mocks.Consumer{} 575 notifier.On("OnBlockIncorporated", mock.Anything).Return(nil) 576 notifier.On("OnFinalizedBlock", mock.Anything).Return(nil) 577 finalizationCallback := &mockm.Finalizer{} 578 finalizationCallback.On("MakeFinal", mock.Anything).Return(nil) 579 finalizationCallback.On("MakeValid", mock.Anything).Return(nil) 580 581 genesisBQ := makeGenesis() 582 583 fin, err := finalizer.New(genesisBQ, finalizationCallback, notifier) 584 585 require.Nil(t, err) 586 return fin, notifier, finalizationCallback 587 } 588 589 func addBlocksToFinalizer(fin forks.Finalizer, blocks []*model.Block) error { 590 for _, block := range blocks { 591 err := fin.AddBlock(block) 592 if err != nil { 593 return fmt.Errorf("test case failed at adding block: %v: %w", block.View, err) 594 } 595 } 596 597 return nil 598 } 599 600 // check the view and QC's view of the locked block for the finalizer 601 func assertTheLockedBlock(t *testing.T, fin forks.Finalizer, qc int, view int) { 602 assert.Equal(t, fin.LockedBlock().View, uint64(view), "locked block has wrong view") 603 assert.Equal(t, fin.LockedBlock().QC.View, uint64(qc), "locked block has wrong qc") 604 } 605 606 // check the view and QC's view of the finalized block for the finalizer 607 func assertFinalizedBlock(t *testing.T, fin forks.Finalizer, qc int, view int) { 608 assert.Equal(t, fin.FinalizedBlock().View, uint64(view), "finalized block has wrong view") 609 assert.Equal(t, fin.FinalizedBlock().QC.View, uint64(qc), "fianlized block has wrong qc") 610 }