github.com/MetalBlockchain/metalgo@v1.11.9/vms/proposervm/pre_fork_block_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 proposervm 5 6 import ( 7 "bytes" 8 "context" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 "go.uber.org/mock/gomock" 14 15 "github.com/MetalBlockchain/metalgo/database" 16 "github.com/MetalBlockchain/metalgo/ids" 17 "github.com/MetalBlockchain/metalgo/snow" 18 "github.com/MetalBlockchain/metalgo/snow/choices" 19 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman" 20 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman/snowmantest" 21 "github.com/MetalBlockchain/metalgo/snow/engine/snowman/block" 22 "github.com/MetalBlockchain/metalgo/snow/validators" 23 "github.com/MetalBlockchain/metalgo/utils/logging" 24 "github.com/MetalBlockchain/metalgo/utils/timer/mockable" 25 26 statelessblock "github.com/MetalBlockchain/metalgo/vms/proposervm/block" 27 ) 28 29 func TestOracle_PreForkBlkImplementsInterface(t *testing.T) { 30 require := require.New(t) 31 32 // setup 33 proBlk := preForkBlock{ 34 Block: snowmantest.BuildChild(snowmantest.Genesis), 35 } 36 37 // test 38 _, err := proBlk.Options(context.Background()) 39 require.Equal(snowman.ErrNotOracle, err) 40 41 // setup 42 proBlk = preForkBlock{ 43 Block: &TestOptionsBlock{}, 44 } 45 46 // test 47 _, err = proBlk.Options(context.Background()) 48 require.NoError(err) 49 } 50 51 func TestOracle_PreForkBlkCanBuiltOnPreForkOption(t *testing.T) { 52 require := require.New(t) 53 54 var ( 55 activationTime = mockable.MaxTime 56 durangoTime = activationTime 57 ) 58 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 59 defer func() { 60 require.NoError(proVM.Shutdown(context.Background())) 61 }() 62 63 // create pre fork oracle block ... 64 coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis) 65 preferredTestBlk := snowmantest.BuildChild(coreTestBlk) 66 oracleCoreBlk := &TestOptionsBlock{ 67 Block: *coreTestBlk, 68 opts: [2]snowman.Block{ 69 preferredTestBlk, 70 snowmantest.BuildChild(coreTestBlk), 71 }, 72 } 73 74 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 75 return oracleCoreBlk, nil 76 } 77 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 78 switch blkID { 79 case snowmantest.GenesisID: 80 return snowmantest.Genesis, nil 81 case oracleCoreBlk.ID(): 82 return oracleCoreBlk, nil 83 case oracleCoreBlk.opts[0].ID(): 84 return oracleCoreBlk.opts[0], nil 85 case oracleCoreBlk.opts[1].ID(): 86 return oracleCoreBlk.opts[1], nil 87 default: 88 return nil, database.ErrNotFound 89 } 90 } 91 92 parentBlk, err := proVM.BuildBlock(context.Background()) 93 require.NoError(err) 94 95 // retrieve options ... 96 require.IsType(&preForkBlock{}, parentBlk) 97 preForkOracleBlk := parentBlk.(*preForkBlock) 98 opts, err := preForkOracleBlk.Options(context.Background()) 99 require.NoError(err) 100 require.NoError(opts[0].Verify(context.Background())) 101 102 // ... show a block can be built on top of an option 103 require.NoError(proVM.SetPreference(context.Background(), opts[0].ID())) 104 105 lastCoreBlk := &TestOptionsBlock{ 106 Block: *snowmantest.BuildChild(preferredTestBlk), 107 } 108 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 109 return lastCoreBlk, nil 110 } 111 112 preForkChild, err := proVM.BuildBlock(context.Background()) 113 require.NoError(err) 114 require.IsType(&preForkBlock{}, preForkChild) 115 } 116 117 func TestOracle_PostForkBlkCanBuiltOnPreForkOption(t *testing.T) { 118 require := require.New(t) 119 120 var ( 121 activationTime = snowmantest.GenesisTimestamp.Add(10 * time.Second) 122 durangoTime = activationTime 123 ) 124 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 125 defer func() { 126 require.NoError(proVM.Shutdown(context.Background())) 127 }() 128 129 // create pre fork oracle block pre activation time... 130 coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis) 131 coreTestBlk.TimestampV = activationTime.Add(-1 * time.Second) 132 133 // ... whose options are post activation time 134 preferredBlk := snowmantest.BuildChild(coreTestBlk) 135 preferredBlk.TimestampV = activationTime.Add(time.Second) 136 137 unpreferredBlk := snowmantest.BuildChild(coreTestBlk) 138 unpreferredBlk.TimestampV = activationTime.Add(time.Second) 139 140 oracleCoreBlk := &TestOptionsBlock{ 141 Block: *coreTestBlk, 142 opts: [2]snowman.Block{ 143 preferredBlk, 144 unpreferredBlk, 145 }, 146 } 147 148 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 149 return oracleCoreBlk, nil 150 } 151 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 152 switch blkID { 153 case snowmantest.GenesisID: 154 return snowmantest.Genesis, nil 155 case oracleCoreBlk.ID(): 156 return oracleCoreBlk, nil 157 case oracleCoreBlk.opts[0].ID(): 158 return oracleCoreBlk.opts[0], nil 159 case oracleCoreBlk.opts[1].ID(): 160 return oracleCoreBlk.opts[1], nil 161 default: 162 return nil, database.ErrNotFound 163 } 164 } 165 166 parentBlk, err := proVM.BuildBlock(context.Background()) 167 require.NoError(err) 168 169 // retrieve options ... 170 require.IsType(&preForkBlock{}, parentBlk) 171 preForkOracleBlk := parentBlk.(*preForkBlock) 172 opts, err := preForkOracleBlk.Options(context.Background()) 173 require.NoError(err) 174 require.NoError(opts[0].Verify(context.Background())) 175 176 // ... show a block can be built on top of an option 177 require.NoError(proVM.SetPreference(context.Background(), opts[0].ID())) 178 179 lastCoreBlk := &TestOptionsBlock{ 180 Block: *snowmantest.BuildChild(preferredBlk), 181 } 182 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 183 return lastCoreBlk, nil 184 } 185 186 postForkChild, err := proVM.BuildBlock(context.Background()) 187 require.NoError(err) 188 require.IsType(&postForkBlock{}, postForkChild) 189 } 190 191 func TestBlockVerify_PreFork_ParentChecks(t *testing.T) { 192 require := require.New(t) 193 194 var ( 195 activationTime = snowmantest.GenesisTimestamp.Add(10 * time.Second) 196 durangoTime = activationTime 197 ) 198 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 199 defer func() { 200 require.NoError(proVM.Shutdown(context.Background())) 201 }() 202 203 // create parent block ... 204 parentCoreBlk := snowmantest.BuildChild(snowmantest.Genesis) 205 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 206 return parentCoreBlk, nil 207 } 208 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 209 switch blkID { 210 case snowmantest.GenesisID: 211 return snowmantest.Genesis, nil 212 case parentCoreBlk.ID(): 213 return parentCoreBlk, nil 214 default: 215 return nil, database.ErrNotFound 216 } 217 } 218 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 219 switch { 220 case bytes.Equal(b, snowmantest.GenesisBytes): 221 return snowmantest.Genesis, nil 222 case bytes.Equal(b, parentCoreBlk.Bytes()): 223 return parentCoreBlk, nil 224 default: 225 return nil, database.ErrNotFound 226 } 227 } 228 229 parentBlk, err := proVM.BuildBlock(context.Background()) 230 require.NoError(err) 231 232 // .. create child block ... 233 childCoreBlk := snowmantest.BuildChild(parentCoreBlk) 234 childBlk := preForkBlock{ 235 Block: childCoreBlk, 236 vm: proVM, 237 } 238 239 { 240 // child block referring unknown parent does not verify 241 childCoreBlk.ParentV = ids.Empty 242 err = childBlk.Verify(context.Background()) 243 require.ErrorIs(err, database.ErrNotFound) 244 } 245 246 { 247 // child block referring known parent does verify 248 childCoreBlk.ParentV = parentBlk.ID() 249 require.NoError(childBlk.Verify(context.Background())) 250 } 251 } 252 253 func TestBlockVerify_BlocksBuiltOnPreForkGenesis(t *testing.T) { 254 require := require.New(t) 255 256 var ( 257 activationTime = snowmantest.GenesisTimestamp.Add(10 * time.Second) 258 durangoTime = activationTime 259 ) 260 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 261 defer func() { 262 require.NoError(proVM.Shutdown(context.Background())) 263 }() 264 265 preActivationTime := activationTime.Add(-1 * time.Second) 266 proVM.Set(preActivationTime) 267 268 coreBlk := snowmantest.BuildChild(snowmantest.Genesis) 269 coreBlk.TimestampV = preActivationTime 270 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 271 return coreBlk, nil 272 } 273 274 // preFork block verifies if parent is before fork activation time 275 preForkChild, err := proVM.BuildBlock(context.Background()) 276 require.NoError(err) 277 require.IsType(&preForkBlock{}, preForkChild) 278 279 require.NoError(preForkChild.Verify(context.Background())) 280 281 // postFork block does NOT verify if parent is before fork activation time 282 postForkStatelessChild, err := statelessblock.Build( 283 snowmantest.GenesisID, 284 coreBlk.Timestamp(), 285 0, // pChainHeight 286 proVM.StakingCertLeaf, 287 coreBlk.Bytes(), 288 proVM.ctx.ChainID, 289 proVM.StakingLeafSigner, 290 ) 291 require.NoError(err) 292 postForkChild := &postForkBlock{ 293 SignedBlock: postForkStatelessChild, 294 postForkCommonComponents: postForkCommonComponents{ 295 vm: proVM, 296 innerBlk: coreBlk, 297 status: choices.Processing, 298 }, 299 } 300 301 require.True(postForkChild.Timestamp().Before(activationTime)) 302 err = postForkChild.Verify(context.Background()) 303 require.ErrorIs(err, errProposersNotActivated) 304 305 // once activation time is crossed postForkBlock are produced 306 postActivationTime := activationTime.Add(time.Second) 307 proVM.Set(postActivationTime) 308 309 coreVM.SetPreferenceF = func(context.Context, ids.ID) error { 310 return nil 311 } 312 require.NoError(proVM.SetPreference(context.Background(), preForkChild.ID())) 313 314 secondCoreBlk := snowmantest.BuildChild(coreBlk) 315 secondCoreBlk.TimestampV = postActivationTime 316 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 317 return secondCoreBlk, nil 318 } 319 coreVM.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) { 320 switch id { 321 case snowmantest.GenesisID: 322 return snowmantest.Genesis, nil 323 case coreBlk.ID(): 324 return coreBlk, nil 325 default: 326 require.FailNow("attempt to get unknown block") 327 return nil, nil 328 } 329 } 330 331 lastPreForkBlk, err := proVM.BuildBlock(context.Background()) 332 require.NoError(err) 333 require.IsType(&preForkBlock{}, lastPreForkBlk) 334 335 require.NoError(lastPreForkBlk.Verify(context.Background())) 336 337 require.NoError(proVM.SetPreference(context.Background(), lastPreForkBlk.ID())) 338 thirdCoreBlk := snowmantest.BuildChild(secondCoreBlk) 339 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 340 return thirdCoreBlk, nil 341 } 342 coreVM.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) { 343 switch id { 344 case snowmantest.GenesisID: 345 return snowmantest.Genesis, nil 346 case coreBlk.ID(): 347 return coreBlk, nil 348 case secondCoreBlk.ID(): 349 return secondCoreBlk, nil 350 default: 351 require.FailNow("attempt to get unknown block") 352 return nil, nil 353 } 354 } 355 356 firstPostForkBlk, err := proVM.BuildBlock(context.Background()) 357 require.NoError(err) 358 require.IsType(&postForkBlock{}, firstPostForkBlk) 359 360 require.NoError(firstPostForkBlk.Verify(context.Background())) 361 } 362 363 func TestBlockVerify_BlocksBuiltOnPostForkGenesis(t *testing.T) { 364 require := require.New(t) 365 366 var ( 367 activationTime = snowmantest.GenesisTimestamp.Add(-1 * time.Second) 368 durangoTime = activationTime 369 ) 370 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 371 proVM.Set(activationTime) 372 defer func() { 373 require.NoError(proVM.Shutdown(context.Background())) 374 }() 375 376 // build parent block after fork activation time ... 377 coreBlock := snowmantest.BuildChild(snowmantest.Genesis) 378 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 379 return coreBlock, nil 380 } 381 382 // postFork block verifies if parent is after fork activation time 383 postForkChild, err := proVM.BuildBlock(context.Background()) 384 require.NoError(err) 385 require.IsType(&postForkBlock{}, postForkChild) 386 387 require.NoError(postForkChild.Verify(context.Background())) 388 389 // preFork block does NOT verify if parent is after fork activation time 390 preForkChild := preForkBlock{ 391 Block: coreBlock, 392 vm: proVM, 393 } 394 err = preForkChild.Verify(context.Background()) 395 require.ErrorIs(err, errUnexpectedBlockType) 396 } 397 398 func TestBlockAccept_PreFork_SetsLastAcceptedBlock(t *testing.T) { 399 require := require.New(t) 400 401 // setup 402 var ( 403 activationTime = mockable.MaxTime 404 durangoTime = activationTime 405 ) 406 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 407 defer func() { 408 require.NoError(proVM.Shutdown(context.Background())) 409 }() 410 411 coreBlk := snowmantest.BuildChild(snowmantest.Genesis) 412 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 413 return coreBlk, nil 414 } 415 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 416 switch blkID { 417 case snowmantest.GenesisID: 418 return snowmantest.Genesis, nil 419 case coreBlk.ID(): 420 return coreBlk, nil 421 default: 422 return nil, database.ErrNotFound 423 } 424 } 425 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 426 switch { 427 case bytes.Equal(b, snowmantest.GenesisBytes): 428 return snowmantest.Genesis, nil 429 case bytes.Equal(b, coreBlk.Bytes()): 430 return coreBlk, nil 431 default: 432 return nil, errUnknownBlock 433 } 434 } 435 436 builtBlk, err := proVM.BuildBlock(context.Background()) 437 require.NoError(err) 438 439 // test 440 require.NoError(builtBlk.Accept(context.Background())) 441 442 coreVM.LastAcceptedF = func(context.Context) (ids.ID, error) { 443 if coreBlk.Status() == choices.Accepted { 444 return coreBlk.ID(), nil 445 } 446 return snowmantest.GenesisID, nil 447 } 448 acceptedID, err := proVM.LastAccepted(context.Background()) 449 require.NoError(err) 450 require.Equal(builtBlk.ID(), acceptedID) 451 } 452 453 // ProposerBlock.Reject tests section 454 func TestBlockReject_PreForkBlock_InnerBlockIsRejected(t *testing.T) { 455 require := require.New(t) 456 457 var ( 458 activationTime = mockable.MaxTime 459 durangoTime = activationTime 460 ) 461 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 462 defer func() { 463 require.NoError(proVM.Shutdown(context.Background())) 464 }() 465 466 coreBlk := snowmantest.BuildChild(snowmantest.Genesis) 467 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 468 return coreBlk, nil 469 } 470 471 sb, err := proVM.BuildBlock(context.Background()) 472 require.NoError(err) 473 require.IsType(&preForkBlock{}, sb) 474 proBlk := sb.(*preForkBlock) 475 476 require.NoError(proBlk.Reject(context.Background())) 477 require.Equal(choices.Rejected, proBlk.Status()) 478 require.Equal(choices.Rejected, proBlk.Block.Status()) 479 } 480 481 func TestBlockVerify_ForkBlockIsOracleBlock(t *testing.T) { 482 require := require.New(t) 483 484 var ( 485 activationTime = snowmantest.GenesisTimestamp.Add(10 * time.Second) 486 durangoTime = activationTime 487 ) 488 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 489 defer func() { 490 require.NoError(proVM.Shutdown(context.Background())) 491 }() 492 493 postActivationTime := activationTime.Add(time.Second) 494 proVM.Set(postActivationTime) 495 496 coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis) 497 coreTestBlk.TimestampV = postActivationTime 498 coreBlk := &TestOptionsBlock{ 499 Block: *coreTestBlk, 500 opts: [2]snowman.Block{ 501 snowmantest.BuildChild(coreTestBlk), 502 snowmantest.BuildChild(coreTestBlk), 503 }, 504 } 505 506 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 507 switch blkID { 508 case snowmantest.GenesisID: 509 return snowmantest.Genesis, nil 510 case coreBlk.ID(): 511 return coreBlk, nil 512 case coreBlk.opts[0].ID(): 513 return coreBlk.opts[0], nil 514 case coreBlk.opts[1].ID(): 515 return coreBlk.opts[1], nil 516 default: 517 return nil, database.ErrNotFound 518 } 519 } 520 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 521 switch { 522 case bytes.Equal(b, snowmantest.GenesisBytes): 523 return snowmantest.Genesis, nil 524 case bytes.Equal(b, coreBlk.Bytes()): 525 return coreBlk, nil 526 case bytes.Equal(b, coreBlk.opts[0].Bytes()): 527 return coreBlk.opts[0], nil 528 case bytes.Equal(b, coreBlk.opts[1].Bytes()): 529 return coreBlk.opts[1], nil 530 default: 531 return nil, errUnknownBlock 532 } 533 } 534 535 firstBlock, err := proVM.ParseBlock(context.Background(), coreBlk.Bytes()) 536 require.NoError(err) 537 538 require.NoError(firstBlock.Verify(context.Background())) 539 540 oracleBlock, ok := firstBlock.(snowman.OracleBlock) 541 require.True(ok) 542 543 options, err := oracleBlock.Options(context.Background()) 544 require.NoError(err) 545 546 require.NoError(options[0].Verify(context.Background())) 547 548 require.NoError(options[1].Verify(context.Background())) 549 } 550 551 func TestBlockVerify_ForkBlockIsOracleBlockButChildrenAreSigned(t *testing.T) { 552 require := require.New(t) 553 554 var ( 555 activationTime = snowmantest.GenesisTimestamp.Add(10 * time.Second) 556 durangoTime = activationTime 557 ) 558 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 559 defer func() { 560 require.NoError(proVM.Shutdown(context.Background())) 561 }() 562 563 postActivationTime := activationTime.Add(time.Second) 564 proVM.Set(postActivationTime) 565 566 coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis) 567 coreTestBlk.TimestampV = postActivationTime 568 coreBlk := &TestOptionsBlock{ 569 Block: *coreTestBlk, 570 opts: [2]snowman.Block{ 571 snowmantest.BuildChild(coreTestBlk), 572 snowmantest.BuildChild(coreTestBlk), 573 }, 574 } 575 576 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 577 switch blkID { 578 case snowmantest.GenesisID: 579 return snowmantest.Genesis, nil 580 case coreBlk.ID(): 581 return coreBlk, nil 582 case coreBlk.opts[0].ID(): 583 return coreBlk.opts[0], nil 584 case coreBlk.opts[1].ID(): 585 return coreBlk.opts[1], nil 586 default: 587 return nil, database.ErrNotFound 588 } 589 } 590 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 591 switch { 592 case bytes.Equal(b, snowmantest.GenesisBytes): 593 return snowmantest.Genesis, nil 594 case bytes.Equal(b, coreBlk.Bytes()): 595 return coreBlk, nil 596 case bytes.Equal(b, coreBlk.opts[0].Bytes()): 597 return coreBlk.opts[0], nil 598 case bytes.Equal(b, coreBlk.opts[1].Bytes()): 599 return coreBlk.opts[1], nil 600 default: 601 return nil, errUnknownBlock 602 } 603 } 604 605 firstBlock, err := proVM.ParseBlock(context.Background(), coreBlk.Bytes()) 606 require.NoError(err) 607 608 require.NoError(firstBlock.Verify(context.Background())) 609 610 slb, err := statelessblock.Build( 611 firstBlock.ID(), // refer unknown parent 612 firstBlock.Timestamp(), 613 0, // pChainHeight, 614 proVM.StakingCertLeaf, 615 coreBlk.opts[0].Bytes(), 616 proVM.ctx.ChainID, 617 proVM.StakingLeafSigner, 618 ) 619 require.NoError(err) 620 621 invalidChild, err := proVM.ParseBlock(context.Background(), slb.Bytes()) 622 if err != nil { 623 // A failure to parse is okay here 624 return 625 } 626 627 err = invalidChild.Verify(context.Background()) 628 require.ErrorIs(err, errUnexpectedBlockType) 629 } 630 631 // Assert that when the underlying VM implements ChainVMWithBuildBlockContext 632 // and the proposervm is activated, we only call the VM's BuildBlockWithContext 633 // when a P-chain height can be correctly provided from the parent block. 634 func TestPreForkBlock_BuildBlockWithContext(t *testing.T) { 635 require := require.New(t) 636 ctrl := gomock.NewController(t) 637 638 pChainHeight := uint64(1337) 639 blkID := ids.GenerateTestID() 640 innerBlk := snowmantest.NewMockBlock(ctrl) 641 innerBlk.EXPECT().ID().Return(blkID).AnyTimes() 642 innerBlk.EXPECT().Timestamp().Return(mockable.MaxTime) 643 builtBlk := snowmantest.NewMockBlock(ctrl) 644 builtBlk.EXPECT().Bytes().Return([]byte{1, 2, 3}).AnyTimes() 645 builtBlk.EXPECT().ID().Return(ids.GenerateTestID()).AnyTimes() 646 builtBlk.EXPECT().Height().Return(pChainHeight).AnyTimes() 647 innerVM := block.NewMockChainVM(ctrl) 648 innerVM.EXPECT().BuildBlock(gomock.Any()).Return(builtBlk, nil).AnyTimes() 649 vdrState := validators.NewMockState(ctrl) 650 vdrState.EXPECT().GetMinimumHeight(context.Background()).Return(pChainHeight, nil).AnyTimes() 651 652 vm := &VM{ 653 ChainVM: innerVM, 654 ctx: &snow.Context{ 655 ValidatorState: vdrState, 656 Log: logging.NoLog{}, 657 }, 658 } 659 660 blk := &preForkBlock{ 661 Block: innerBlk, 662 vm: vm, 663 } 664 665 // Should call BuildBlock since proposervm won't have a P-chain height 666 gotChild, err := blk.buildChild(context.Background()) 667 require.NoError(err) 668 require.Equal(builtBlk, gotChild.(*postForkBlock).innerBlk) 669 670 // Should call BuildBlock since proposervm is not activated 671 innerBlk.EXPECT().Timestamp().Return(time.Time{}) 672 vm.ActivationTime = mockable.MaxTime 673 674 gotChild, err = blk.buildChild(context.Background()) 675 require.NoError(err) 676 require.Equal(builtBlk, gotChild.(*preForkBlock).Block) 677 }