github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/block/executor/verifier_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package executor 5 6 import ( 7 "context" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/require" 12 "go.uber.org/mock/gomock" 13 14 "github.com/MetalBlockchain/metalgo/chains/atomic" 15 "github.com/MetalBlockchain/metalgo/database" 16 "github.com/MetalBlockchain/metalgo/ids" 17 "github.com/MetalBlockchain/metalgo/snow" 18 "github.com/MetalBlockchain/metalgo/utils/logging" 19 "github.com/MetalBlockchain/metalgo/utils/set" 20 "github.com/MetalBlockchain/metalgo/utils/timer/mockable" 21 "github.com/MetalBlockchain/metalgo/vms/components/verify" 22 "github.com/MetalBlockchain/metalgo/vms/platformvm/block" 23 "github.com/MetalBlockchain/metalgo/vms/platformvm/config" 24 "github.com/MetalBlockchain/metalgo/vms/platformvm/state" 25 "github.com/MetalBlockchain/metalgo/vms/platformvm/status" 26 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 27 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs/executor" 28 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs/mempool" 29 "github.com/MetalBlockchain/metalgo/vms/platformvm/upgrade" 30 ) 31 32 func TestVerifierVisitProposalBlock(t *testing.T) { 33 require := require.New(t) 34 ctrl := gomock.NewController(t) 35 36 s := state.NewMockState(ctrl) 37 mempool := mempool.NewMockMempool(ctrl) 38 parentID := ids.GenerateTestID() 39 parentStatelessBlk := block.NewMockBlock(ctrl) 40 parentOnAcceptState := state.NewMockDiff(ctrl) 41 timestamp := time.Now() 42 // One call for each of onCommitState and onAbortState. 43 parentOnAcceptState.EXPECT().GetTimestamp().Return(timestamp).Times(2) 44 45 backend := &backend{ 46 lastAccepted: parentID, 47 blkIDToState: map[ids.ID]*blockState{ 48 parentID: { 49 statelessBlock: parentStatelessBlk, 50 onAcceptState: parentOnAcceptState, 51 }, 52 }, 53 Mempool: mempool, 54 state: s, 55 ctx: &snow.Context{ 56 Log: logging.NoLog{}, 57 }, 58 } 59 verifier := &verifier{ 60 txExecutorBackend: &executor.Backend{ 61 Config: &config.Config{ 62 UpgradeConfig: upgrade.Config{ 63 BanffTime: mockable.MaxTime, // banff is not activated 64 }, 65 }, 66 Clk: &mockable.Clock{}, 67 }, 68 backend: backend, 69 } 70 manager := &manager{ 71 backend: backend, 72 verifier: verifier, 73 } 74 75 blkTx := txs.NewMockUnsignedTx(ctrl) 76 blkTx.EXPECT().Visit(gomock.AssignableToTypeOf(&executor.ProposalTxExecutor{})).Return(nil).Times(1) 77 78 // We can't serialize [blkTx] because it isn't 79 // registered with the blocks.Codec. 80 // Serialize this block with a dummy tx 81 // and replace it after creation with the mock tx. 82 // TODO allow serialization of mock txs. 83 apricotBlk, err := block.NewApricotProposalBlock( 84 parentID, 85 2, 86 &txs.Tx{ 87 Unsigned: &txs.AdvanceTimeTx{}, 88 Creds: []verify.Verifiable{}, 89 }, 90 ) 91 require.NoError(err) 92 apricotBlk.Tx.Unsigned = blkTx 93 94 // Set expectations for dependencies. 95 tx := apricotBlk.Txs()[0] 96 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 97 mempool.EXPECT().Remove([]*txs.Tx{tx}).Times(1) 98 99 // Visit the block 100 blk := manager.NewBlock(apricotBlk) 101 require.NoError(blk.Verify(context.Background())) 102 require.Contains(verifier.backend.blkIDToState, apricotBlk.ID()) 103 gotBlkState := verifier.backend.blkIDToState[apricotBlk.ID()] 104 require.Equal(apricotBlk, gotBlkState.statelessBlock) 105 require.Equal(timestamp, gotBlkState.timestamp) 106 107 // Assert that the expected tx statuses are set. 108 _, gotStatus, err := gotBlkState.onCommitState.GetTx(tx.ID()) 109 require.NoError(err) 110 require.Equal(status.Committed, gotStatus) 111 112 _, gotStatus, err = gotBlkState.onAbortState.GetTx(tx.ID()) 113 require.NoError(err) 114 require.Equal(status.Aborted, gotStatus) 115 116 // Visiting again should return nil without using dependencies. 117 require.NoError(blk.Verify(context.Background())) 118 } 119 120 func TestVerifierVisitAtomicBlock(t *testing.T) { 121 require := require.New(t) 122 ctrl := gomock.NewController(t) 123 124 // Create mocked dependencies. 125 s := state.NewMockState(ctrl) 126 mempool := mempool.NewMockMempool(ctrl) 127 parentID := ids.GenerateTestID() 128 parentStatelessBlk := block.NewMockBlock(ctrl) 129 grandparentID := ids.GenerateTestID() 130 parentState := state.NewMockDiff(ctrl) 131 132 backend := &backend{ 133 blkIDToState: map[ids.ID]*blockState{ 134 parentID: { 135 statelessBlock: parentStatelessBlk, 136 onAcceptState: parentState, 137 }, 138 }, 139 Mempool: mempool, 140 state: s, 141 ctx: &snow.Context{ 142 Log: logging.NoLog{}, 143 }, 144 } 145 verifier := &verifier{ 146 txExecutorBackend: &executor.Backend{ 147 Config: &config.Config{ 148 UpgradeConfig: upgrade.Config{ 149 ApricotPhase5Time: time.Now().Add(time.Hour), 150 BanffTime: mockable.MaxTime, // banff is not activated 151 }, 152 }, 153 Clk: &mockable.Clock{}, 154 }, 155 backend: backend, 156 } 157 manager := &manager{ 158 backend: backend, 159 verifier: verifier, 160 } 161 162 onAccept := state.NewMockDiff(ctrl) 163 blkTx := txs.NewMockUnsignedTx(ctrl) 164 inputs := set.Of(ids.GenerateTestID()) 165 blkTx.EXPECT().Visit(gomock.AssignableToTypeOf(&executor.AtomicTxExecutor{})).DoAndReturn( 166 func(e *executor.AtomicTxExecutor) error { 167 e.OnAccept = onAccept 168 e.Inputs = inputs 169 return nil 170 }, 171 ).Times(1) 172 173 // We can't serialize [blkTx] because it isn't registered with blocks.Codec. 174 // Serialize this block with a dummy tx and replace it after creation with 175 // the mock tx. 176 // TODO allow serialization of mock txs. 177 apricotBlk, err := block.NewApricotAtomicBlock( 178 parentID, 179 2, 180 &txs.Tx{ 181 Unsigned: &txs.AdvanceTimeTx{}, 182 Creds: []verify.Verifiable{}, 183 }, 184 ) 185 require.NoError(err) 186 apricotBlk.Tx.Unsigned = blkTx 187 188 // Set expectations for dependencies. 189 timestamp := time.Now() 190 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 191 parentStatelessBlk.EXPECT().Parent().Return(grandparentID).Times(1) 192 mempool.EXPECT().Remove([]*txs.Tx{apricotBlk.Tx}).Times(1) 193 onAccept.EXPECT().AddTx(apricotBlk.Tx, status.Committed).Times(1) 194 onAccept.EXPECT().GetTimestamp().Return(timestamp).Times(1) 195 196 blk := manager.NewBlock(apricotBlk) 197 require.NoError(blk.Verify(context.Background())) 198 199 require.Contains(verifier.backend.blkIDToState, apricotBlk.ID()) 200 gotBlkState := verifier.backend.blkIDToState[apricotBlk.ID()] 201 require.Equal(apricotBlk, gotBlkState.statelessBlock) 202 require.Equal(onAccept, gotBlkState.onAcceptState) 203 require.Equal(inputs, gotBlkState.inputs) 204 require.Equal(timestamp, gotBlkState.timestamp) 205 206 // Visiting again should return nil without using dependencies. 207 require.NoError(blk.Verify(context.Background())) 208 } 209 210 func TestVerifierVisitStandardBlock(t *testing.T) { 211 require := require.New(t) 212 ctrl := gomock.NewController(t) 213 214 // Create mocked dependencies. 215 s := state.NewMockState(ctrl) 216 mempool := mempool.NewMockMempool(ctrl) 217 parentID := ids.GenerateTestID() 218 parentStatelessBlk := block.NewMockBlock(ctrl) 219 parentState := state.NewMockDiff(ctrl) 220 221 backend := &backend{ 222 blkIDToState: map[ids.ID]*blockState{ 223 parentID: { 224 statelessBlock: parentStatelessBlk, 225 onAcceptState: parentState, 226 }, 227 }, 228 Mempool: mempool, 229 state: s, 230 ctx: &snow.Context{ 231 Log: logging.NoLog{}, 232 }, 233 } 234 verifier := &verifier{ 235 txExecutorBackend: &executor.Backend{ 236 Config: &config.Config{ 237 UpgradeConfig: upgrade.Config{ 238 ApricotPhase5Time: time.Now().Add(time.Hour), 239 BanffTime: mockable.MaxTime, // banff is not activated 240 }, 241 }, 242 Clk: &mockable.Clock{}, 243 }, 244 backend: backend, 245 } 246 manager := &manager{ 247 backend: backend, 248 verifier: verifier, 249 } 250 251 blkTx := txs.NewMockUnsignedTx(ctrl) 252 atomicRequests := map[ids.ID]*atomic.Requests{ 253 ids.GenerateTestID(): { 254 RemoveRequests: [][]byte{{1}, {2}}, 255 PutRequests: []*atomic.Element{ 256 { 257 Key: []byte{3}, 258 Value: []byte{4}, 259 Traits: [][]byte{{5}, {6}}, 260 }, 261 }, 262 }, 263 } 264 blkTx.EXPECT().Visit(gomock.AssignableToTypeOf(&executor.StandardTxExecutor{})).DoAndReturn( 265 func(e *executor.StandardTxExecutor) error { 266 e.OnAccept = func() {} 267 e.Inputs = set.Set[ids.ID]{} 268 e.AtomicRequests = atomicRequests 269 return nil 270 }, 271 ).Times(1) 272 273 // We can't serialize [blkTx] because it isn't 274 // registered with the blocks.Codec. 275 // Serialize this block with a dummy tx 276 // and replace it after creation with the mock tx. 277 // TODO allow serialization of mock txs. 278 apricotBlk, err := block.NewApricotStandardBlock( 279 parentID, 280 2, /*height*/ 281 []*txs.Tx{ 282 { 283 Unsigned: &txs.AdvanceTimeTx{}, 284 Creds: []verify.Verifiable{}, 285 }, 286 }, 287 ) 288 require.NoError(err) 289 apricotBlk.Transactions[0].Unsigned = blkTx 290 291 // Set expectations for dependencies. 292 timestamp := time.Now() 293 parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) 294 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 295 mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) 296 297 blk := manager.NewBlock(apricotBlk) 298 require.NoError(blk.Verify(context.Background())) 299 300 // Assert expected state. 301 require.Contains(verifier.backend.blkIDToState, apricotBlk.ID()) 302 gotBlkState := verifier.backend.blkIDToState[apricotBlk.ID()] 303 require.Equal(apricotBlk, gotBlkState.statelessBlock) 304 require.Equal(set.Set[ids.ID]{}, gotBlkState.inputs) 305 require.Equal(timestamp, gotBlkState.timestamp) 306 307 // Visiting again should return nil without using dependencies. 308 require.NoError(blk.Verify(context.Background())) 309 } 310 311 func TestVerifierVisitCommitBlock(t *testing.T) { 312 require := require.New(t) 313 ctrl := gomock.NewController(t) 314 315 // Create mocked dependencies. 316 s := state.NewMockState(ctrl) 317 mempool := mempool.NewMockMempool(ctrl) 318 parentID := ids.GenerateTestID() 319 parentStatelessBlk := block.NewMockBlock(ctrl) 320 parentOnDecisionState := state.NewMockDiff(ctrl) 321 parentOnCommitState := state.NewMockDiff(ctrl) 322 parentOnAbortState := state.NewMockDiff(ctrl) 323 324 backend := &backend{ 325 blkIDToState: map[ids.ID]*blockState{ 326 parentID: { 327 statelessBlock: parentStatelessBlk, 328 proposalBlockState: proposalBlockState{ 329 onDecisionState: parentOnDecisionState, 330 onCommitState: parentOnCommitState, 331 onAbortState: parentOnAbortState, 332 }, 333 }, 334 }, 335 Mempool: mempool, 336 state: s, 337 ctx: &snow.Context{ 338 Log: logging.NoLog{}, 339 }, 340 } 341 verifier := &verifier{ 342 txExecutorBackend: &executor.Backend{ 343 Config: &config.Config{ 344 UpgradeConfig: upgrade.Config{ 345 BanffTime: mockable.MaxTime, // banff is not activated 346 }, 347 }, 348 Clk: &mockable.Clock{}, 349 }, 350 backend: backend, 351 } 352 manager := &manager{ 353 backend: backend, 354 verifier: verifier, 355 } 356 357 apricotBlk, err := block.NewApricotCommitBlock( 358 parentID, 359 2, 360 ) 361 require.NoError(err) 362 363 // Set expectations for dependencies. 364 timestamp := time.Now() 365 gomock.InOrder( 366 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1), 367 parentOnCommitState.EXPECT().GetTimestamp().Return(timestamp).Times(1), 368 ) 369 370 // Verify the block. 371 blk := manager.NewBlock(apricotBlk) 372 require.NoError(blk.Verify(context.Background())) 373 374 // Assert expected state. 375 require.Contains(verifier.backend.blkIDToState, apricotBlk.ID()) 376 gotBlkState := verifier.backend.blkIDToState[apricotBlk.ID()] 377 require.Equal(parentOnAbortState, gotBlkState.onAcceptState) 378 require.Equal(timestamp, gotBlkState.timestamp) 379 380 // Visiting again should return nil without using dependencies. 381 require.NoError(blk.Verify(context.Background())) 382 } 383 384 func TestVerifierVisitAbortBlock(t *testing.T) { 385 require := require.New(t) 386 ctrl := gomock.NewController(t) 387 388 // Create mocked dependencies. 389 s := state.NewMockState(ctrl) 390 mempool := mempool.NewMockMempool(ctrl) 391 parentID := ids.GenerateTestID() 392 parentStatelessBlk := block.NewMockBlock(ctrl) 393 parentOnDecisionState := state.NewMockDiff(ctrl) 394 parentOnCommitState := state.NewMockDiff(ctrl) 395 parentOnAbortState := state.NewMockDiff(ctrl) 396 397 backend := &backend{ 398 blkIDToState: map[ids.ID]*blockState{ 399 parentID: { 400 statelessBlock: parentStatelessBlk, 401 proposalBlockState: proposalBlockState{ 402 onDecisionState: parentOnDecisionState, 403 onCommitState: parentOnCommitState, 404 onAbortState: parentOnAbortState, 405 }, 406 }, 407 }, 408 Mempool: mempool, 409 state: s, 410 ctx: &snow.Context{ 411 Log: logging.NoLog{}, 412 }, 413 } 414 verifier := &verifier{ 415 txExecutorBackend: &executor.Backend{ 416 Config: &config.Config{ 417 UpgradeConfig: upgrade.Config{ 418 BanffTime: mockable.MaxTime, // banff is not activated 419 }, 420 }, 421 Clk: &mockable.Clock{}, 422 }, 423 backend: backend, 424 } 425 manager := &manager{ 426 backend: backend, 427 verifier: verifier, 428 } 429 430 apricotBlk, err := block.NewApricotAbortBlock( 431 parentID, 432 2, 433 ) 434 require.NoError(err) 435 436 // Set expectations for dependencies. 437 timestamp := time.Now() 438 gomock.InOrder( 439 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1), 440 parentOnAbortState.EXPECT().GetTimestamp().Return(timestamp).Times(1), 441 ) 442 443 // Verify the block. 444 blk := manager.NewBlock(apricotBlk) 445 require.NoError(blk.Verify(context.Background())) 446 447 // Assert expected state. 448 require.Contains(verifier.backend.blkIDToState, apricotBlk.ID()) 449 gotBlkState := verifier.backend.blkIDToState[apricotBlk.ID()] 450 require.Equal(parentOnAbortState, gotBlkState.onAcceptState) 451 require.Equal(timestamp, gotBlkState.timestamp) 452 453 // Visiting again should return nil without using dependencies. 454 require.NoError(blk.Verify(context.Background())) 455 } 456 457 // Assert that a block with an unverified parent fails verification. 458 func TestVerifyUnverifiedParent(t *testing.T) { 459 require := require.New(t) 460 ctrl := gomock.NewController(t) 461 462 // Create mocked dependencies. 463 s := state.NewMockState(ctrl) 464 mempool := mempool.NewMockMempool(ctrl) 465 parentID := ids.GenerateTestID() 466 467 backend := &backend{ 468 blkIDToState: map[ids.ID]*blockState{}, 469 Mempool: mempool, 470 state: s, 471 ctx: &snow.Context{ 472 Log: logging.NoLog{}, 473 }, 474 } 475 verifier := &verifier{ 476 txExecutorBackend: &executor.Backend{ 477 Config: &config.Config{ 478 UpgradeConfig: upgrade.Config{ 479 BanffTime: mockable.MaxTime, // banff is not activated 480 }, 481 }, 482 Clk: &mockable.Clock{}, 483 }, 484 backend: backend, 485 } 486 487 blk, err := block.NewApricotAbortBlock(parentID /*not in memory or persisted state*/, 2 /*height*/) 488 require.NoError(err) 489 490 // Set expectations for dependencies. 491 s.EXPECT().GetTimestamp().Return(time.Now()).Times(1) 492 s.EXPECT().GetStatelessBlock(parentID).Return(nil, database.ErrNotFound).Times(1) 493 494 // Verify the block. 495 err = blk.Visit(verifier) 496 require.ErrorIs(err, database.ErrNotFound) 497 } 498 499 func TestBanffAbortBlockTimestampChecks(t *testing.T) { 500 ctrl := gomock.NewController(t) 501 502 now := defaultGenesisTime.Add(time.Hour) 503 504 tests := []struct { 505 description string 506 parentTime time.Time 507 childTime time.Time 508 result error 509 }{ 510 { 511 description: "abort block timestamp matching parent's one", 512 parentTime: now, 513 childTime: now, 514 result: nil, 515 }, 516 { 517 description: "abort block timestamp before parent's one", 518 childTime: now.Add(-1 * time.Second), 519 parentTime: now, 520 result: errOptionBlockTimestampNotMatchingParent, 521 }, 522 { 523 description: "abort block timestamp after parent's one", 524 parentTime: now, 525 childTime: now.Add(time.Second), 526 result: errOptionBlockTimestampNotMatchingParent, 527 }, 528 } 529 530 for _, test := range tests { 531 t.Run(test.description, func(t *testing.T) { 532 require := require.New(t) 533 534 // Create mocked dependencies. 535 s := state.NewMockState(ctrl) 536 mempool := mempool.NewMockMempool(ctrl) 537 parentID := ids.GenerateTestID() 538 parentStatelessBlk := block.NewMockBlock(ctrl) 539 parentHeight := uint64(1) 540 541 backend := &backend{ 542 blkIDToState: make(map[ids.ID]*blockState), 543 Mempool: mempool, 544 state: s, 545 ctx: &snow.Context{ 546 Log: logging.NoLog{}, 547 }, 548 } 549 verifier := &verifier{ 550 txExecutorBackend: &executor.Backend{ 551 Config: &config.Config{ 552 UpgradeConfig: upgrade.Config{ 553 BanffTime: time.Time{}, // banff is activated 554 }, 555 }, 556 Clk: &mockable.Clock{}, 557 }, 558 backend: backend, 559 } 560 561 // build and verify child block 562 childHeight := parentHeight + 1 563 statelessAbortBlk, err := block.NewBanffAbortBlock(test.childTime, parentID, childHeight) 564 require.NoError(err) 565 566 // setup parent state 567 parentTime := defaultGenesisTime 568 s.EXPECT().GetLastAccepted().Return(parentID).Times(3) 569 s.EXPECT().GetTimestamp().Return(parentTime).Times(3) 570 571 onDecisionState, err := state.NewDiff(parentID, backend) 572 require.NoError(err) 573 onCommitState, err := state.NewDiff(parentID, backend) 574 require.NoError(err) 575 onAbortState, err := state.NewDiff(parentID, backend) 576 require.NoError(err) 577 backend.blkIDToState[parentID] = &blockState{ 578 timestamp: test.parentTime, 579 statelessBlock: parentStatelessBlk, 580 proposalBlockState: proposalBlockState{ 581 onDecisionState: onDecisionState, 582 onCommitState: onCommitState, 583 onAbortState: onAbortState, 584 }, 585 } 586 587 // Set expectations for dependencies. 588 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 589 590 err = statelessAbortBlk.Visit(verifier) 591 require.ErrorIs(err, test.result) 592 }) 593 } 594 } 595 596 // TODO combine with TestApricotCommitBlockTimestampChecks 597 func TestBanffCommitBlockTimestampChecks(t *testing.T) { 598 ctrl := gomock.NewController(t) 599 600 now := defaultGenesisTime.Add(time.Hour) 601 602 tests := []struct { 603 description string 604 parentTime time.Time 605 childTime time.Time 606 result error 607 }{ 608 { 609 description: "commit block timestamp matching parent's one", 610 parentTime: now, 611 childTime: now, 612 result: nil, 613 }, 614 { 615 description: "commit block timestamp before parent's one", 616 childTime: now.Add(-1 * time.Second), 617 parentTime: now, 618 result: errOptionBlockTimestampNotMatchingParent, 619 }, 620 { 621 description: "commit block timestamp after parent's one", 622 parentTime: now, 623 childTime: now.Add(time.Second), 624 result: errOptionBlockTimestampNotMatchingParent, 625 }, 626 } 627 628 for _, test := range tests { 629 t.Run(test.description, func(t *testing.T) { 630 require := require.New(t) 631 632 // Create mocked dependencies. 633 s := state.NewMockState(ctrl) 634 mempool := mempool.NewMockMempool(ctrl) 635 parentID := ids.GenerateTestID() 636 parentStatelessBlk := block.NewMockBlock(ctrl) 637 parentHeight := uint64(1) 638 639 backend := &backend{ 640 blkIDToState: make(map[ids.ID]*blockState), 641 Mempool: mempool, 642 state: s, 643 ctx: &snow.Context{ 644 Log: logging.NoLog{}, 645 }, 646 } 647 verifier := &verifier{ 648 txExecutorBackend: &executor.Backend{ 649 Config: &config.Config{ 650 UpgradeConfig: upgrade.Config{ 651 BanffTime: time.Time{}, // banff is activated 652 }, 653 }, 654 Clk: &mockable.Clock{}, 655 }, 656 backend: backend, 657 } 658 659 // build and verify child block 660 childHeight := parentHeight + 1 661 statelessCommitBlk, err := block.NewBanffCommitBlock(test.childTime, parentID, childHeight) 662 require.NoError(err) 663 664 // setup parent state 665 parentTime := defaultGenesisTime 666 s.EXPECT().GetLastAccepted().Return(parentID).Times(3) 667 s.EXPECT().GetTimestamp().Return(parentTime).Times(3) 668 669 onDecisionState, err := state.NewDiff(parentID, backend) 670 require.NoError(err) 671 onCommitState, err := state.NewDiff(parentID, backend) 672 require.NoError(err) 673 onAbortState, err := state.NewDiff(parentID, backend) 674 require.NoError(err) 675 backend.blkIDToState[parentID] = &blockState{ 676 timestamp: test.parentTime, 677 statelessBlock: parentStatelessBlk, 678 proposalBlockState: proposalBlockState{ 679 onDecisionState: onDecisionState, 680 onCommitState: onCommitState, 681 onAbortState: onAbortState, 682 }, 683 } 684 685 // Set expectations for dependencies. 686 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 687 688 err = statelessCommitBlk.Visit(verifier) 689 require.ErrorIs(err, test.result) 690 }) 691 } 692 } 693 694 func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { 695 require := require.New(t) 696 ctrl := gomock.NewController(t) 697 698 // Create mocked dependencies. 699 s := state.NewMockState(ctrl) 700 mempool := mempool.NewMockMempool(ctrl) 701 702 grandParentID := ids.GenerateTestID() 703 grandParentStatelessBlk := block.NewMockBlock(ctrl) 704 grandParentState := state.NewMockDiff(ctrl) 705 parentID := ids.GenerateTestID() 706 parentStatelessBlk := block.NewMockBlock(ctrl) 707 parentState := state.NewMockDiff(ctrl) 708 atomicInputs := set.Of(ids.GenerateTestID()) 709 710 backend := &backend{ 711 blkIDToState: map[ids.ID]*blockState{ 712 grandParentID: { 713 statelessBlock: grandParentStatelessBlk, 714 onAcceptState: grandParentState, 715 inputs: atomicInputs, 716 }, 717 parentID: { 718 statelessBlock: parentStatelessBlk, 719 onAcceptState: parentState, 720 }, 721 }, 722 Mempool: mempool, 723 state: s, 724 ctx: &snow.Context{ 725 Log: logging.NoLog{}, 726 }, 727 } 728 verifier := &verifier{ 729 txExecutorBackend: &executor.Backend{ 730 Config: &config.Config{ 731 UpgradeConfig: upgrade.Config{ 732 ApricotPhase5Time: time.Now().Add(time.Hour), 733 BanffTime: mockable.MaxTime, // banff is not activated 734 }, 735 }, 736 Clk: &mockable.Clock{}, 737 }, 738 backend: backend, 739 } 740 741 blkTx := txs.NewMockUnsignedTx(ctrl) 742 atomicRequests := map[ids.ID]*atomic.Requests{ 743 ids.GenerateTestID(): { 744 RemoveRequests: [][]byte{{1}, {2}}, 745 PutRequests: []*atomic.Element{ 746 { 747 Key: []byte{3}, 748 Value: []byte{4}, 749 Traits: [][]byte{{5}, {6}}, 750 }, 751 }, 752 }, 753 } 754 blkTx.EXPECT().Visit(gomock.AssignableToTypeOf(&executor.StandardTxExecutor{})).DoAndReturn( 755 func(e *executor.StandardTxExecutor) error { 756 e.OnAccept = func() {} 757 e.Inputs = atomicInputs 758 e.AtomicRequests = atomicRequests 759 return nil 760 }, 761 ).Times(1) 762 763 // We can't serialize [blkTx] because it isn't 764 // registered with the blocks.Codec. 765 // Serialize this block with a dummy tx 766 // and replace it after creation with the mock tx. 767 // TODO allow serialization of mock txs. 768 blk, err := block.NewApricotStandardBlock( 769 parentID, 770 2, 771 []*txs.Tx{ 772 { 773 Unsigned: &txs.AdvanceTimeTx{}, 774 Creds: []verify.Verifiable{}, 775 }, 776 }, 777 ) 778 require.NoError(err) 779 blk.Transactions[0].Unsigned = blkTx 780 781 // Set expectations for dependencies. 782 timestamp := time.Now() 783 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 784 parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) 785 parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) 786 787 err = verifier.ApricotStandardBlock(blk) 788 require.ErrorIs(err, errConflictingParentTxs) 789 } 790 791 func TestVerifierVisitApricotStandardBlockWithProposalBlockParent(t *testing.T) { 792 require := require.New(t) 793 ctrl := gomock.NewController(t) 794 795 // Create mocked dependencies. 796 s := state.NewMockState(ctrl) 797 mempool := mempool.NewMockMempool(ctrl) 798 parentID := ids.GenerateTestID() 799 parentStatelessBlk := block.NewMockBlock(ctrl) 800 parentOnCommitState := state.NewMockDiff(ctrl) 801 parentOnAbortState := state.NewMockDiff(ctrl) 802 803 backend := &backend{ 804 blkIDToState: map[ids.ID]*blockState{ 805 parentID: { 806 statelessBlock: parentStatelessBlk, 807 proposalBlockState: proposalBlockState{ 808 onCommitState: parentOnCommitState, 809 onAbortState: parentOnAbortState, 810 }, 811 }, 812 }, 813 Mempool: mempool, 814 state: s, 815 ctx: &snow.Context{ 816 Log: logging.NoLog{}, 817 }, 818 } 819 verifier := &verifier{ 820 txExecutorBackend: &executor.Backend{ 821 Config: &config.Config{ 822 UpgradeConfig: upgrade.Config{ 823 BanffTime: mockable.MaxTime, // banff is not activated 824 }, 825 }, 826 Clk: &mockable.Clock{}, 827 }, 828 backend: backend, 829 } 830 831 blk, err := block.NewApricotStandardBlock( 832 parentID, 833 2, 834 []*txs.Tx{ 835 { 836 Unsigned: &txs.AdvanceTimeTx{}, 837 Creds: []verify.Verifiable{}, 838 }, 839 }, 840 ) 841 require.NoError(err) 842 843 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 844 845 err = verifier.ApricotStandardBlock(blk) 846 require.ErrorIs(err, state.ErrMissingParentState) 847 } 848 849 func TestVerifierVisitBanffStandardBlockWithProposalBlockParent(t *testing.T) { 850 require := require.New(t) 851 ctrl := gomock.NewController(t) 852 853 // Create mocked dependencies. 854 s := state.NewMockState(ctrl) 855 mempool := mempool.NewMockMempool(ctrl) 856 parentID := ids.GenerateTestID() 857 parentStatelessBlk := block.NewMockBlock(ctrl) 858 parentTime := time.Now() 859 parentOnCommitState := state.NewMockDiff(ctrl) 860 parentOnAbortState := state.NewMockDiff(ctrl) 861 862 backend := &backend{ 863 blkIDToState: map[ids.ID]*blockState{ 864 parentID: { 865 statelessBlock: parentStatelessBlk, 866 proposalBlockState: proposalBlockState{ 867 onCommitState: parentOnCommitState, 868 onAbortState: parentOnAbortState, 869 }, 870 }, 871 }, 872 Mempool: mempool, 873 state: s, 874 ctx: &snow.Context{ 875 Log: logging.NoLog{}, 876 }, 877 } 878 verifier := &verifier{ 879 txExecutorBackend: &executor.Backend{ 880 Config: &config.Config{ 881 UpgradeConfig: upgrade.Config{ 882 BanffTime: time.Time{}, // banff is activated 883 }, 884 }, 885 Clk: &mockable.Clock{}, 886 }, 887 backend: backend, 888 } 889 890 blk, err := block.NewBanffStandardBlock( 891 parentTime.Add(time.Second), 892 parentID, 893 2, 894 []*txs.Tx{ 895 { 896 Unsigned: &txs.AdvanceTimeTx{}, 897 Creds: []verify.Verifiable{}, 898 }, 899 }, 900 ) 901 require.NoError(err) 902 903 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 904 905 err = verifier.BanffStandardBlock(blk) 906 require.ErrorIs(err, state.ErrMissingParentState) 907 } 908 909 func TestVerifierVisitApricotCommitBlockUnexpectedParentState(t *testing.T) { 910 require := require.New(t) 911 ctrl := gomock.NewController(t) 912 913 // Create mocked dependencies. 914 s := state.NewMockState(ctrl) 915 parentID := ids.GenerateTestID() 916 parentStatelessBlk := block.NewMockBlock(ctrl) 917 verifier := &verifier{ 918 txExecutorBackend: &executor.Backend{ 919 Config: &config.Config{ 920 UpgradeConfig: upgrade.Config{ 921 BanffTime: mockable.MaxTime, // banff is not activated 922 }, 923 }, 924 Clk: &mockable.Clock{}, 925 }, 926 backend: &backend{ 927 blkIDToState: map[ids.ID]*blockState{ 928 parentID: { 929 statelessBlock: parentStatelessBlk, 930 }, 931 }, 932 state: s, 933 ctx: &snow.Context{ 934 Log: logging.NoLog{}, 935 }, 936 }, 937 } 938 939 blk, err := block.NewApricotCommitBlock( 940 parentID, 941 2, 942 ) 943 require.NoError(err) 944 945 // Set expectations for dependencies. 946 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 947 948 // Verify the block. 949 err = verifier.ApricotCommitBlock(blk) 950 require.ErrorIs(err, state.ErrMissingParentState) 951 } 952 953 func TestVerifierVisitBanffCommitBlockUnexpectedParentState(t *testing.T) { 954 require := require.New(t) 955 ctrl := gomock.NewController(t) 956 957 // Create mocked dependencies. 958 s := state.NewMockState(ctrl) 959 parentID := ids.GenerateTestID() 960 parentStatelessBlk := block.NewMockBlock(ctrl) 961 timestamp := time.Unix(12345, 0) 962 verifier := &verifier{ 963 txExecutorBackend: &executor.Backend{ 964 Config: &config.Config{ 965 UpgradeConfig: upgrade.Config{ 966 BanffTime: time.Time{}, // banff is activated 967 }, 968 }, 969 Clk: &mockable.Clock{}, 970 }, 971 backend: &backend{ 972 blkIDToState: map[ids.ID]*blockState{ 973 parentID: { 974 statelessBlock: parentStatelessBlk, 975 timestamp: timestamp, 976 }, 977 }, 978 state: s, 979 ctx: &snow.Context{ 980 Log: logging.NoLog{}, 981 }, 982 }, 983 } 984 985 blk, err := block.NewBanffCommitBlock( 986 timestamp, 987 parentID, 988 2, 989 ) 990 require.NoError(err) 991 992 // Set expectations for dependencies. 993 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 994 995 // Verify the block. 996 err = verifier.BanffCommitBlock(blk) 997 require.ErrorIs(err, state.ErrMissingParentState) 998 } 999 1000 func TestVerifierVisitApricotAbortBlockUnexpectedParentState(t *testing.T) { 1001 require := require.New(t) 1002 ctrl := gomock.NewController(t) 1003 1004 // Create mocked dependencies. 1005 s := state.NewMockState(ctrl) 1006 parentID := ids.GenerateTestID() 1007 parentStatelessBlk := block.NewMockBlock(ctrl) 1008 verifier := &verifier{ 1009 txExecutorBackend: &executor.Backend{ 1010 Config: &config.Config{ 1011 UpgradeConfig: upgrade.Config{ 1012 BanffTime: mockable.MaxTime, // banff is not activated 1013 }, 1014 }, 1015 Clk: &mockable.Clock{}, 1016 }, 1017 backend: &backend{ 1018 blkIDToState: map[ids.ID]*blockState{ 1019 parentID: { 1020 statelessBlock: parentStatelessBlk, 1021 }, 1022 }, 1023 state: s, 1024 ctx: &snow.Context{ 1025 Log: logging.NoLog{}, 1026 }, 1027 }, 1028 } 1029 1030 blk, err := block.NewApricotAbortBlock( 1031 parentID, 1032 2, 1033 ) 1034 require.NoError(err) 1035 1036 // Set expectations for dependencies. 1037 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 1038 1039 // Verify the block. 1040 err = verifier.ApricotAbortBlock(blk) 1041 require.ErrorIs(err, state.ErrMissingParentState) 1042 } 1043 1044 func TestVerifierVisitBanffAbortBlockUnexpectedParentState(t *testing.T) { 1045 require := require.New(t) 1046 ctrl := gomock.NewController(t) 1047 1048 // Create mocked dependencies. 1049 s := state.NewMockState(ctrl) 1050 parentID := ids.GenerateTestID() 1051 parentStatelessBlk := block.NewMockBlock(ctrl) 1052 timestamp := time.Unix(12345, 0) 1053 verifier := &verifier{ 1054 txExecutorBackend: &executor.Backend{ 1055 Config: &config.Config{ 1056 UpgradeConfig: upgrade.Config{ 1057 BanffTime: time.Time{}, // banff is activated 1058 }, 1059 }, 1060 Clk: &mockable.Clock{}, 1061 }, 1062 backend: &backend{ 1063 blkIDToState: map[ids.ID]*blockState{ 1064 parentID: { 1065 statelessBlock: parentStatelessBlk, 1066 timestamp: timestamp, 1067 }, 1068 }, 1069 state: s, 1070 ctx: &snow.Context{ 1071 Log: logging.NoLog{}, 1072 }, 1073 }, 1074 } 1075 1076 blk, err := block.NewBanffAbortBlock( 1077 timestamp, 1078 parentID, 1079 2, 1080 ) 1081 require.NoError(err) 1082 1083 // Set expectations for dependencies. 1084 parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) 1085 1086 // Verify the block. 1087 err = verifier.BanffAbortBlock(blk) 1088 require.ErrorIs(err, state.ErrMissingParentState) 1089 }