github.com/MetalBlockchain/metalgo@v1.11.9/vms/proposervm/batched_vm_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/prometheus/client_golang/prometheus" 13 "github.com/stretchr/testify/require" 14 15 "github.com/MetalBlockchain/metalgo/database" 16 "github.com/MetalBlockchain/metalgo/database/memdb" 17 "github.com/MetalBlockchain/metalgo/database/prefixdb" 18 "github.com/MetalBlockchain/metalgo/ids" 19 "github.com/MetalBlockchain/metalgo/snow" 20 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman" 21 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman/snowmantest" 22 "github.com/MetalBlockchain/metalgo/snow/engine/common" 23 "github.com/MetalBlockchain/metalgo/snow/engine/snowman/block" 24 "github.com/MetalBlockchain/metalgo/snow/snowtest" 25 "github.com/MetalBlockchain/metalgo/snow/validators" 26 "github.com/MetalBlockchain/metalgo/utils/timer/mockable" 27 ) 28 29 func TestCoreVMNotRemote(t *testing.T) { 30 // if coreVM is not remote VM, a specific error is returned 31 require := require.New(t) 32 var ( 33 activationTime = time.Unix(0, 0) 34 durangoTime = activationTime 35 ) 36 _, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 37 defer func() { 38 require.NoError(proVM.Shutdown(context.Background())) 39 }() 40 41 blkID := ids.Empty 42 maxBlocksNum := 1000 // a high value to get all built blocks 43 maxBlocksSize := 1000000 // a high value to get all built blocks 44 maxBlocksRetrivalTime := time.Hour // a high value to get all built blocks 45 _, err := proVM.GetAncestors( 46 context.Background(), 47 blkID, 48 maxBlocksNum, 49 maxBlocksSize, 50 maxBlocksRetrivalTime, 51 ) 52 require.ErrorIs(err, block.ErrRemoteVMNotImplemented) 53 54 var blks [][]byte 55 _, err = proVM.BatchedParseBlock(context.Background(), blks) 56 require.ErrorIs(err, block.ErrRemoteVMNotImplemented) 57 } 58 59 func TestGetAncestorsPreForkOnly(t *testing.T) { 60 require := require.New(t) 61 var ( 62 activationTime = mockable.MaxTime 63 durangoTime = activationTime 64 ) 65 coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime) 66 defer func() { 67 require.NoError(proRemoteVM.Shutdown(context.Background())) 68 }() 69 70 // Build some prefork blocks.... 71 coreBlk1 := snowmantest.BuildChild(snowmantest.Genesis) 72 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 73 return coreBlk1, nil 74 } 75 builtBlk1, err := proRemoteVM.BuildBlock(context.Background()) 76 require.NoError(err) 77 78 // prepare build of next block 79 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk1.ID())) 80 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 81 switch blkID { 82 case coreBlk1.ID(): 83 return coreBlk1, nil 84 default: 85 return nil, errUnknownBlock 86 } 87 } 88 89 coreBlk2 := snowmantest.BuildChild(coreBlk1) 90 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 91 return coreBlk2, nil 92 } 93 builtBlk2, err := proRemoteVM.BuildBlock(context.Background()) 94 require.NoError(err) 95 96 // prepare build of next block 97 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID())) 98 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 99 switch blkID { 100 case coreBlk2.ID(): 101 return coreBlk2, nil 102 default: 103 return nil, errUnknownBlock 104 } 105 } 106 107 coreBlk3 := snowmantest.BuildChild(coreBlk2) 108 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 109 return coreBlk3, nil 110 } 111 builtBlk3, err := proRemoteVM.BuildBlock(context.Background()) 112 require.NoError(err) 113 114 // ...Call GetAncestors on them ... 115 // Note: we assumed that if blkID is not known, that's NOT an error. 116 // Simply return an empty result 117 coreVM.GetAncestorsF = func(_ context.Context, blkID ids.ID, _, _ int, _ time.Duration) ([][]byte, error) { 118 res := make([][]byte, 0, 3) 119 switch blkID { 120 case coreBlk3.ID(): 121 res = append(res, coreBlk3.Bytes()) 122 res = append(res, coreBlk2.Bytes()) 123 res = append(res, coreBlk1.Bytes()) 124 return res, nil 125 case coreBlk2.ID(): 126 res = append(res, coreBlk2.Bytes()) 127 res = append(res, coreBlk1.Bytes()) 128 return res, nil 129 case coreBlk1.ID(): 130 res = append(res, coreBlk1.Bytes()) 131 return res, nil 132 default: 133 return res, nil 134 } 135 } 136 137 reqBlkID := builtBlk3.ID() 138 maxBlocksNum := 1000 // a high value to get all built blocks 139 maxBlocksSize := 1000000 // a high value to get all built blocks 140 maxBlocksRetrivalTime := time.Hour // a high value to get all built blocks 141 res, err := proRemoteVM.GetAncestors( 142 context.Background(), 143 reqBlkID, 144 maxBlocksNum, 145 maxBlocksSize, 146 maxBlocksRetrivalTime, 147 ) 148 149 // ... and check returned values are as expected 150 require.NoError(err) 151 require.Len(res, 3) 152 require.Equal(builtBlk3.Bytes(), res[0]) 153 require.Equal(builtBlk2.Bytes(), res[1]) 154 require.Equal(builtBlk1.Bytes(), res[2]) 155 156 // another good call 157 reqBlkID = builtBlk1.ID() 158 res, err = proRemoteVM.GetAncestors( 159 context.Background(), 160 reqBlkID, 161 maxBlocksNum, 162 maxBlocksSize, 163 maxBlocksRetrivalTime, 164 ) 165 require.NoError(err) 166 require.Len(res, 1) 167 require.Equal(builtBlk1.Bytes(), res[0]) 168 169 // a faulty call 170 reqBlkID = ids.Empty 171 res, err = proRemoteVM.GetAncestors( 172 context.Background(), 173 reqBlkID, 174 maxBlocksNum, 175 maxBlocksSize, 176 maxBlocksRetrivalTime, 177 ) 178 require.NoError(err) 179 require.Empty(res) 180 } 181 182 func TestGetAncestorsPostForkOnly(t *testing.T) { 183 require := require.New(t) 184 var ( 185 activationTime = time.Unix(0, 0) 186 durangoTime = activationTime 187 ) 188 coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime) 189 defer func() { 190 require.NoError(proRemoteVM.Shutdown(context.Background())) 191 }() 192 193 // Build some post-Fork blocks.... 194 coreBlk1 := snowmantest.BuildChild(snowmantest.Genesis) 195 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 196 return coreBlk1, nil 197 } 198 builtBlk1, err := proRemoteVM.BuildBlock(context.Background()) 199 require.NoError(err) 200 201 // prepare build of next block 202 require.NoError(builtBlk1.Verify(context.Background())) 203 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk1.ID())) 204 require.NoError(waitForProposerWindow(proRemoteVM, builtBlk1, 0)) 205 206 coreBlk2 := snowmantest.BuildChild(coreBlk1) 207 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 208 return coreBlk2, nil 209 } 210 builtBlk2, err := proRemoteVM.BuildBlock(context.Background()) 211 require.NoError(err) 212 213 // prepare build of next block 214 require.NoError(builtBlk2.Verify(context.Background())) 215 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID())) 216 require.NoError(waitForProposerWindow(proRemoteVM, builtBlk2, 0)) 217 218 coreBlk3 := snowmantest.BuildChild(coreBlk2) 219 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 220 return coreBlk3, nil 221 } 222 builtBlk3, err := proRemoteVM.BuildBlock(context.Background()) 223 require.NoError(err) 224 225 require.NoError(builtBlk3.Verify(context.Background())) 226 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk3.ID())) 227 228 // ...Call GetAncestors on them ... 229 // Note: we assumed that if blkID is not known, that's NOT an error. 230 // Simply return an empty result 231 coreVM.GetAncestorsF = func(_ context.Context, blkID ids.ID, _, _ int, _ time.Duration) ([][]byte, error) { 232 res := make([][]byte, 0, 3) 233 switch blkID { 234 case coreBlk3.ID(): 235 res = append(res, coreBlk3.Bytes()) 236 res = append(res, coreBlk2.Bytes()) 237 res = append(res, coreBlk1.Bytes()) 238 return res, nil 239 case coreBlk2.ID(): 240 res = append(res, coreBlk2.Bytes()) 241 res = append(res, coreBlk1.Bytes()) 242 return res, nil 243 case coreBlk1.ID(): 244 res = append(res, coreBlk1.Bytes()) 245 return res, nil 246 default: 247 return res, nil 248 } 249 } 250 251 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 252 switch { 253 case bytes.Equal(b, snowmantest.GenesisBytes): 254 return snowmantest.Genesis, nil 255 case bytes.Equal(b, coreBlk1.Bytes()): 256 return coreBlk1, nil 257 case bytes.Equal(b, coreBlk2.Bytes()): 258 return coreBlk2, nil 259 case bytes.Equal(b, coreBlk3.Bytes()): 260 return coreBlk3, nil 261 default: 262 return nil, errUnknownBlock 263 } 264 } 265 266 reqBlkID := builtBlk3.ID() 267 maxBlocksNum := 1000 // a high value to get all built blocks 268 maxBlocksSize := 1000000 // a high value to get all built blocks 269 maxBlocksRetrivalTime := time.Hour // a high value to get all built blocks 270 res, err := proRemoteVM.GetAncestors( 271 context.Background(), 272 reqBlkID, 273 maxBlocksNum, 274 maxBlocksSize, 275 maxBlocksRetrivalTime, 276 ) 277 278 // ... and check returned values are as expected 279 require.NoError(err) 280 require.Len(res, 3) 281 require.Equal(builtBlk3.Bytes(), res[0]) 282 require.Equal(builtBlk2.Bytes(), res[1]) 283 require.Equal(builtBlk1.Bytes(), res[2]) 284 285 // another good call 286 reqBlkID = builtBlk1.ID() 287 res, err = proRemoteVM.GetAncestors( 288 context.Background(), 289 reqBlkID, 290 maxBlocksNum, 291 maxBlocksSize, 292 maxBlocksRetrivalTime, 293 ) 294 require.NoError(err) 295 require.Len(res, 1) 296 require.Equal(builtBlk1.Bytes(), res[0]) 297 298 // a faulty call 299 reqBlkID = ids.Empty 300 res, err = proRemoteVM.GetAncestors( 301 context.Background(), 302 reqBlkID, 303 maxBlocksNum, 304 maxBlocksSize, 305 maxBlocksRetrivalTime, 306 ) 307 require.NoError(err) 308 require.Empty(res) 309 } 310 311 func TestGetAncestorsAtSnomanPlusPlusFork(t *testing.T) { 312 require := require.New(t) 313 314 var ( 315 currentTime = time.Now().Truncate(time.Second) 316 preForkTime = currentTime.Add(5 * time.Minute) 317 forkTime = currentTime.Add(10 * time.Minute) 318 postForkTime = currentTime.Add(15 * time.Minute) 319 320 durangoTime = forkTime 321 ) 322 323 // enable ProBlks in next future 324 coreVM, proRemoteVM := initTestRemoteProposerVM(t, forkTime, durangoTime) 325 defer func() { 326 require.NoError(proRemoteVM.Shutdown(context.Background())) 327 }() 328 329 // Build some prefork blocks.... 330 proRemoteVM.Set(preForkTime) 331 coreBlk1 := snowmantest.BuildChild(snowmantest.Genesis) 332 coreBlk1.TimestampV = preForkTime 333 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 334 return coreBlk1, nil 335 } 336 builtBlk1, err := proRemoteVM.BuildBlock(context.Background()) 337 require.NoError(err) 338 require.IsType(&preForkBlock{}, builtBlk1) 339 340 // prepare build of next block 341 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk1.ID())) 342 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 343 switch { 344 case blkID == coreBlk1.ID(): 345 return coreBlk1, nil 346 default: 347 return nil, errUnknownBlock 348 } 349 } 350 351 coreBlk2 := snowmantest.BuildChild(coreBlk1) 352 coreBlk2.TimestampV = postForkTime 353 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 354 return coreBlk2, nil 355 } 356 builtBlk2, err := proRemoteVM.BuildBlock(context.Background()) 357 require.NoError(err) 358 require.IsType(&preForkBlock{}, builtBlk2) 359 360 // prepare build of next block 361 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID())) 362 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 363 switch { 364 case blkID == coreBlk2.ID(): 365 return coreBlk2, nil 366 default: 367 return nil, errUnknownBlock 368 } 369 } 370 371 // .. and some post-fork 372 proRemoteVM.Set(postForkTime) 373 coreBlk3 := snowmantest.BuildChild(coreBlk2) 374 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 375 return coreBlk3, nil 376 } 377 builtBlk3, err := proRemoteVM.BuildBlock(context.Background()) 378 require.NoError(err) 379 require.IsType(&postForkBlock{}, builtBlk3) 380 381 // prepare build of next block 382 require.NoError(builtBlk3.Verify(context.Background())) 383 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk3.ID())) 384 require.NoError(waitForProposerWindow(proRemoteVM, builtBlk3, builtBlk3.(*postForkBlock).PChainHeight())) 385 386 coreBlk4 := snowmantest.BuildChild(coreBlk3) 387 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 388 return coreBlk4, nil 389 } 390 builtBlk4, err := proRemoteVM.BuildBlock(context.Background()) 391 require.NoError(err) 392 require.IsType(&postForkBlock{}, builtBlk4) 393 require.NoError(builtBlk4.Verify(context.Background())) 394 395 // ...Call GetAncestors on them ... 396 // Note: we assumed that if blkID is not known, that's NOT an error. 397 // Simply return an empty result 398 coreVM.GetAncestorsF = func(_ context.Context, blkID ids.ID, maxBlocksNum, _ int, _ time.Duration) ([][]byte, error) { 399 sortedBlocks := [][]byte{ 400 coreBlk4.Bytes(), 401 coreBlk3.Bytes(), 402 coreBlk2.Bytes(), 403 coreBlk1.Bytes(), 404 } 405 var startIndex int 406 switch blkID { 407 case coreBlk4.ID(): 408 startIndex = 0 409 case coreBlk3.ID(): 410 startIndex = 1 411 case coreBlk2.ID(): 412 startIndex = 2 413 case coreBlk1.ID(): 414 startIndex = 3 415 default: 416 return nil, nil // unknown blockID 417 } 418 419 endIndex := min(startIndex+maxBlocksNum, len(sortedBlocks)) 420 return sortedBlocks[startIndex:endIndex], nil 421 } 422 423 // load all known blocks 424 reqBlkID := builtBlk4.ID() 425 maxBlocksNum := 1000 // an high value to get all built blocks 426 maxBlocksSize := 1000000 // an high value to get all built blocks 427 maxBlocksRetrivalTime := 10 * time.Minute // an high value to get all built blocks 428 res, err := proRemoteVM.GetAncestors( 429 context.Background(), 430 reqBlkID, 431 maxBlocksNum, 432 maxBlocksSize, 433 maxBlocksRetrivalTime, 434 ) 435 436 // ... and check returned values are as expected 437 require.NoError(err) 438 require.Len(res, 4) 439 require.Equal(builtBlk4.Bytes(), res[0]) 440 require.Equal(builtBlk3.Bytes(), res[1]) 441 require.Equal(builtBlk2.Bytes(), res[2]) 442 require.Equal(builtBlk1.Bytes(), res[3]) 443 444 // Regression case: load some prefork and some postfork blocks. 445 reqBlkID = builtBlk4.ID() 446 maxBlocksNum = 3 447 res, err = proRemoteVM.GetAncestors( 448 context.Background(), 449 reqBlkID, 450 maxBlocksNum, 451 maxBlocksSize, 452 maxBlocksRetrivalTime, 453 ) 454 455 // ... and check returned values are as expected 456 require.NoError(err) 457 require.Len(res, 3) 458 require.Equal(builtBlk4.Bytes(), res[0]) 459 require.Equal(builtBlk3.Bytes(), res[1]) 460 require.Equal(builtBlk2.Bytes(), res[2]) 461 462 // another good call 463 reqBlkID = builtBlk1.ID() 464 res, err = proRemoteVM.GetAncestors( 465 context.Background(), 466 reqBlkID, 467 maxBlocksNum, 468 maxBlocksSize, 469 maxBlocksRetrivalTime, 470 ) 471 require.NoError(err) 472 require.Len(res, 1) 473 require.Equal(builtBlk1.Bytes(), res[0]) 474 475 // a faulty call 476 reqBlkID = ids.Empty 477 res, err = proRemoteVM.GetAncestors( 478 context.Background(), 479 reqBlkID, 480 maxBlocksNum, 481 maxBlocksSize, 482 maxBlocksRetrivalTime, 483 ) 484 require.NoError(err) 485 require.Empty(res) 486 } 487 488 func TestBatchedParseBlockPreForkOnly(t *testing.T) { 489 require := require.New(t) 490 var ( 491 activationTime = mockable.MaxTime 492 durangoTime = activationTime 493 ) 494 coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime) 495 defer func() { 496 require.NoError(proRemoteVM.Shutdown(context.Background())) 497 }() 498 499 // Build some prefork blocks.... 500 coreBlk1 := snowmantest.BuildChild(snowmantest.Genesis) 501 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 502 return coreBlk1, nil 503 } 504 builtBlk1, err := proRemoteVM.BuildBlock(context.Background()) 505 require.NoError(err) 506 507 // prepare build of next block 508 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk1.ID())) 509 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 510 switch blkID { 511 case coreBlk1.ID(): 512 return coreBlk1, nil 513 default: 514 return nil, errUnknownBlock 515 } 516 } 517 518 coreBlk2 := snowmantest.BuildChild(coreBlk1) 519 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 520 return coreBlk2, nil 521 } 522 builtBlk2, err := proRemoteVM.BuildBlock(context.Background()) 523 require.NoError(err) 524 525 // prepare build of next block 526 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID())) 527 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 528 switch { 529 case blkID == coreBlk2.ID(): 530 return coreBlk2, nil 531 default: 532 return nil, errUnknownBlock 533 } 534 } 535 536 coreBlk3 := snowmantest.BuildChild(coreBlk2) 537 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 538 return coreBlk3, nil 539 } 540 builtBlk3, err := proRemoteVM.BuildBlock(context.Background()) 541 require.NoError(err) 542 543 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 544 switch { 545 case bytes.Equal(b, coreBlk1.Bytes()): 546 return coreBlk1, nil 547 case bytes.Equal(b, coreBlk2.Bytes()): 548 return coreBlk2, nil 549 case bytes.Equal(b, coreBlk3.Bytes()): 550 return coreBlk3, nil 551 default: 552 return nil, errUnknownBlock 553 } 554 } 555 556 coreVM.BatchedParseBlockF = func(_ context.Context, blks [][]byte) ([]snowman.Block, error) { 557 res := make([]snowman.Block, 0, len(blks)) 558 for _, blkBytes := range blks { 559 switch { 560 case bytes.Equal(blkBytes, coreBlk1.Bytes()): 561 res = append(res, coreBlk1) 562 case bytes.Equal(blkBytes, coreBlk2.Bytes()): 563 res = append(res, coreBlk2) 564 case bytes.Equal(blkBytes, coreBlk3.Bytes()): 565 res = append(res, coreBlk3) 566 default: 567 return nil, errUnknownBlock 568 } 569 } 570 return res, nil 571 } 572 573 bytesToParse := [][]byte{ 574 builtBlk1.Bytes(), 575 builtBlk2.Bytes(), 576 builtBlk3.Bytes(), 577 } 578 res, err := proRemoteVM.BatchedParseBlock(context.Background(), bytesToParse) 579 require.NoError(err) 580 require.Len(res, 3) 581 require.Equal(builtBlk1.ID(), res[0].ID()) 582 require.Equal(builtBlk2.ID(), res[1].ID()) 583 require.Equal(builtBlk3.ID(), res[2].ID()) 584 } 585 586 func TestBatchedParseBlockPostForkOnly(t *testing.T) { 587 require := require.New(t) 588 var ( 589 activationTime = time.Unix(0, 0) 590 durangoTime = activationTime 591 ) 592 coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime) 593 defer func() { 594 require.NoError(proRemoteVM.Shutdown(context.Background())) 595 }() 596 597 // Build some post-Fork blocks.... 598 coreBlk1 := snowmantest.BuildChild(snowmantest.Genesis) 599 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 600 return coreBlk1, nil 601 } 602 builtBlk1, err := proRemoteVM.BuildBlock(context.Background()) 603 require.NoError(err) 604 605 // prepare build of next block 606 require.NoError(builtBlk1.Verify(context.Background())) 607 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk1.ID())) 608 require.NoError(waitForProposerWindow(proRemoteVM, builtBlk1, 0)) 609 610 coreBlk2 := snowmantest.BuildChild(coreBlk1) 611 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 612 return coreBlk2, nil 613 } 614 builtBlk2, err := proRemoteVM.BuildBlock(context.Background()) 615 require.NoError(err) 616 617 // prepare build of next block 618 require.NoError(builtBlk2.Verify(context.Background())) 619 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID())) 620 require.NoError(waitForProposerWindow(proRemoteVM, builtBlk2, builtBlk2.(*postForkBlock).PChainHeight())) 621 622 coreBlk3 := snowmantest.BuildChild(coreBlk2) 623 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 624 return coreBlk3, nil 625 } 626 builtBlk3, err := proRemoteVM.BuildBlock(context.Background()) 627 require.NoError(err) 628 629 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 630 switch { 631 case bytes.Equal(b, coreBlk1.Bytes()): 632 return coreBlk1, nil 633 case bytes.Equal(b, coreBlk2.Bytes()): 634 return coreBlk2, nil 635 case bytes.Equal(b, coreBlk3.Bytes()): 636 return coreBlk3, nil 637 default: 638 return nil, errUnknownBlock 639 } 640 } 641 642 coreVM.BatchedParseBlockF = func(_ context.Context, blks [][]byte) ([]snowman.Block, error) { 643 res := make([]snowman.Block, 0, len(blks)) 644 for _, blkBytes := range blks { 645 switch { 646 case bytes.Equal(blkBytes, coreBlk1.Bytes()): 647 res = append(res, coreBlk1) 648 case bytes.Equal(blkBytes, coreBlk2.Bytes()): 649 res = append(res, coreBlk2) 650 case bytes.Equal(blkBytes, coreBlk3.Bytes()): 651 res = append(res, coreBlk3) 652 default: 653 return nil, errUnknownBlock 654 } 655 } 656 return res, nil 657 } 658 659 bytesToParse := [][]byte{ 660 builtBlk1.Bytes(), 661 builtBlk2.Bytes(), 662 builtBlk3.Bytes(), 663 } 664 res, err := proRemoteVM.BatchedParseBlock(context.Background(), bytesToParse) 665 require.NoError(err) 666 require.Len(res, 3) 667 require.Equal(builtBlk1.ID(), res[0].ID()) 668 require.Equal(builtBlk2.ID(), res[1].ID()) 669 require.Equal(builtBlk3.ID(), res[2].ID()) 670 } 671 672 func TestBatchedParseBlockAtSnomanPlusPlusFork(t *testing.T) { 673 require := require.New(t) 674 675 var ( 676 currentTime = time.Now().Truncate(time.Second) 677 preForkTime = currentTime.Add(5 * time.Minute) 678 forkTime = currentTime.Add(10 * time.Minute) 679 postForkTime = currentTime.Add(15 * time.Minute) 680 681 durangoTime = forkTime 682 ) 683 684 // enable ProBlks in next future 685 coreVM, proRemoteVM := initTestRemoteProposerVM(t, forkTime, durangoTime) 686 defer func() { 687 require.NoError(proRemoteVM.Shutdown(context.Background())) 688 }() 689 690 // Build some prefork blocks.... 691 proRemoteVM.Set(preForkTime) 692 coreBlk1 := snowmantest.BuildChild(snowmantest.Genesis) 693 coreBlk1.TimestampV = preForkTime 694 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 695 return coreBlk1, nil 696 } 697 builtBlk1, err := proRemoteVM.BuildBlock(context.Background()) 698 require.NoError(err) 699 require.IsType(&preForkBlock{}, builtBlk1) 700 701 // prepare build of next block 702 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk1.ID())) 703 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 704 switch { 705 case blkID == coreBlk1.ID(): 706 return coreBlk1, nil 707 default: 708 return nil, errUnknownBlock 709 } 710 } 711 712 coreBlk2 := snowmantest.BuildChild(coreBlk1) 713 coreBlk2.TimestampV = postForkTime 714 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 715 return coreBlk2, nil 716 } 717 builtBlk2, err := proRemoteVM.BuildBlock(context.Background()) 718 require.NoError(err) 719 require.IsType(&preForkBlock{}, builtBlk2) 720 721 // prepare build of next block 722 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID())) 723 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 724 switch { 725 case blkID == coreBlk2.ID(): 726 return coreBlk2, nil 727 default: 728 return nil, errUnknownBlock 729 } 730 } 731 732 // .. and some post-fork 733 proRemoteVM.Set(postForkTime) 734 coreBlk3 := snowmantest.BuildChild(coreBlk2) 735 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 736 return coreBlk3, nil 737 } 738 builtBlk3, err := proRemoteVM.BuildBlock(context.Background()) 739 require.NoError(err) 740 require.IsType(&postForkBlock{}, builtBlk3) 741 742 // prepare build of next block 743 require.NoError(builtBlk3.Verify(context.Background())) 744 require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk3.ID())) 745 require.NoError(waitForProposerWindow(proRemoteVM, builtBlk3, builtBlk3.(*postForkBlock).PChainHeight())) 746 747 coreBlk4 := snowmantest.BuildChild(coreBlk3) 748 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 749 return coreBlk4, nil 750 } 751 builtBlk4, err := proRemoteVM.BuildBlock(context.Background()) 752 require.NoError(err) 753 require.IsType(&postForkBlock{}, builtBlk4) 754 require.NoError(builtBlk4.Verify(context.Background())) 755 756 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 757 switch { 758 case bytes.Equal(b, coreBlk1.Bytes()): 759 return coreBlk1, nil 760 case bytes.Equal(b, coreBlk2.Bytes()): 761 return coreBlk2, nil 762 case bytes.Equal(b, coreBlk3.Bytes()): 763 return coreBlk3, nil 764 case bytes.Equal(b, coreBlk4.Bytes()): 765 return coreBlk4, nil 766 default: 767 return nil, errUnknownBlock 768 } 769 } 770 771 coreVM.BatchedParseBlockF = func(_ context.Context, blks [][]byte) ([]snowman.Block, error) { 772 res := make([]snowman.Block, 0, len(blks)) 773 for _, blkBytes := range blks { 774 switch { 775 case bytes.Equal(blkBytes, coreBlk1.Bytes()): 776 res = append(res, coreBlk1) 777 case bytes.Equal(blkBytes, coreBlk2.Bytes()): 778 res = append(res, coreBlk2) 779 case bytes.Equal(blkBytes, coreBlk3.Bytes()): 780 res = append(res, coreBlk3) 781 case bytes.Equal(blkBytes, coreBlk4.Bytes()): 782 res = append(res, coreBlk4) 783 default: 784 return nil, errUnknownBlock 785 } 786 } 787 return res, nil 788 } 789 790 bytesToParse := [][]byte{ 791 builtBlk4.Bytes(), 792 builtBlk3.Bytes(), 793 builtBlk2.Bytes(), 794 builtBlk1.Bytes(), 795 } 796 797 res, err := proRemoteVM.BatchedParseBlock(context.Background(), bytesToParse) 798 require.NoError(err) 799 require.Len(res, 4) 800 require.Equal(builtBlk4.ID(), res[0].ID()) 801 require.Equal(builtBlk3.ID(), res[1].ID()) 802 require.Equal(builtBlk2.ID(), res[2].ID()) 803 require.Equal(builtBlk1.ID(), res[3].ID()) 804 } 805 806 type TestRemoteProposerVM struct { 807 *block.TestBatchedVM 808 *block.TestVM 809 } 810 811 func initTestRemoteProposerVM( 812 t *testing.T, 813 activationTime, 814 durangoTime time.Time, 815 ) ( 816 TestRemoteProposerVM, 817 *VM, 818 ) { 819 require := require.New(t) 820 821 initialState := []byte("genesis state") 822 coreVM := TestRemoteProposerVM{ 823 TestVM: &block.TestVM{}, 824 TestBatchedVM: &block.TestBatchedVM{}, 825 } 826 coreVM.TestVM.T = t 827 coreVM.TestBatchedVM.T = t 828 829 coreVM.InitializeF = func( 830 context.Context, 831 *snow.Context, 832 database.Database, 833 []byte, 834 []byte, 835 []byte, 836 chan<- common.Message, 837 []*common.Fx, 838 common.AppSender, 839 ) error { 840 return nil 841 } 842 coreVM.LastAcceptedF = func(context.Context) (ids.ID, error) { 843 return snowmantest.GenesisID, nil 844 } 845 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 846 switch blkID { 847 case snowmantest.GenesisID: 848 return snowmantest.Genesis, nil 849 default: 850 return nil, errUnknownBlock 851 } 852 } 853 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 854 switch { 855 case bytes.Equal(b, snowmantest.GenesisBytes): 856 return snowmantest.Genesis, nil 857 default: 858 return nil, errUnknownBlock 859 } 860 } 861 862 proVM := New( 863 coreVM, 864 Config{ 865 ActivationTime: activationTime, 866 DurangoTime: durangoTime, 867 MinimumPChainHeight: 0, 868 MinBlkDelay: DefaultMinBlockDelay, 869 NumHistoricalBlocks: DefaultNumHistoricalBlocks, 870 StakingLeafSigner: pTestSigner, 871 StakingCertLeaf: pTestCert, 872 Registerer: prometheus.NewRegistry(), 873 }, 874 ) 875 876 valState := &validators.TestState{ 877 T: t, 878 } 879 valState.GetMinimumHeightF = func(context.Context) (uint64, error) { 880 return snowmantest.GenesisHeight, nil 881 } 882 valState.GetCurrentHeightF = func(context.Context) (uint64, error) { 883 return defaultPChainHeight, nil 884 } 885 valState.GetValidatorSetF = func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) { 886 var ( 887 thisNode = proVM.ctx.NodeID 888 nodeID1 = ids.BuildTestNodeID([]byte{1}) 889 nodeID2 = ids.BuildTestNodeID([]byte{2}) 890 nodeID3 = ids.BuildTestNodeID([]byte{3}) 891 ) 892 return map[ids.NodeID]*validators.GetValidatorOutput{ 893 thisNode: { 894 NodeID: thisNode, 895 Weight: 10, 896 }, 897 nodeID1: { 898 NodeID: nodeID1, 899 Weight: 5, 900 }, 901 nodeID2: { 902 NodeID: nodeID2, 903 Weight: 6, 904 }, 905 nodeID3: { 906 NodeID: nodeID3, 907 Weight: 7, 908 }, 909 }, nil 910 } 911 912 ctx := snowtest.Context(t, snowtest.CChainID) 913 ctx.NodeID = ids.NodeIDFromCert(pTestCert) 914 ctx.ValidatorState = valState 915 916 require.NoError(proVM.Initialize( 917 context.Background(), 918 ctx, 919 prefixdb.New([]byte{}, memdb.New()), // make sure that DBs are compressed correctly 920 initialState, 921 nil, 922 nil, 923 nil, 924 nil, 925 nil, 926 )) 927 928 // Initialize shouldn't be called again 929 coreVM.InitializeF = nil 930 931 require.NoError(proVM.SetState(context.Background(), snow.NormalOp)) 932 require.NoError(proVM.SetPreference(context.Background(), snowmantest.GenesisID)) 933 return coreVM, proVM 934 }