github.com/ava-labs/avalanchego@v1.11.11/vms/avm/block/executor/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 executor 5 6 import ( 7 "context" 8 "errors" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 "go.uber.org/mock/gomock" 14 15 "github.com/ava-labs/avalanchego/chains/atomic" 16 "github.com/ava-labs/avalanchego/chains/atomic/atomicmock" 17 "github.com/ava-labs/avalanchego/ids" 18 "github.com/ava-labs/avalanchego/snow" 19 "github.com/ava-labs/avalanchego/upgrade/upgradetest" 20 "github.com/ava-labs/avalanchego/utils" 21 "github.com/ava-labs/avalanchego/utils/logging" 22 "github.com/ava-labs/avalanchego/utils/set" 23 "github.com/ava-labs/avalanchego/utils/timer/mockable" 24 "github.com/ava-labs/avalanchego/vms/avm/block" 25 "github.com/ava-labs/avalanchego/vms/avm/config" 26 "github.com/ava-labs/avalanchego/vms/avm/metrics/metricsmock" 27 "github.com/ava-labs/avalanchego/vms/avm/state/statemock" 28 "github.com/ava-labs/avalanchego/vms/avm/txs" 29 "github.com/ava-labs/avalanchego/vms/avm/txs/executor" 30 "github.com/ava-labs/avalanchego/vms/avm/txs/mempool/mempoolmock" 31 "github.com/ava-labs/avalanchego/vms/avm/txs/txsmock" 32 ) 33 34 func TestBlockVerify(t *testing.T) { 35 type test struct { 36 name string 37 blockFunc func(*gomock.Controller) *Block 38 expectedErr error 39 postVerify func(*require.Assertions, *Block) 40 } 41 tests := []test{ 42 { 43 name: "block already verified", 44 blockFunc: func(ctrl *gomock.Controller) *Block { 45 mockBlock := block.NewMockBlock(ctrl) 46 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 47 b := &Block{ 48 Block: mockBlock, 49 manager: &manager{ 50 backend: defaultTestBackend(false, nil), 51 blkIDToState: map[ids.ID]*blockState{}, 52 }, 53 } 54 b.manager.blkIDToState[b.ID()] = &blockState{ 55 statelessBlock: b.Block, 56 } 57 return b 58 }, 59 expectedErr: nil, 60 }, 61 { 62 name: "block timestamp too far in the future", 63 blockFunc: func(ctrl *gomock.Controller) *Block { 64 mockBlock := block.NewMockBlock(ctrl) 65 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 66 mockBlock.EXPECT().MerkleRoot().Return(ids.GenerateTestID()).AnyTimes() 67 return &Block{ 68 Block: mockBlock, 69 manager: &manager{ 70 backend: defaultTestBackend(false, nil), 71 }, 72 } 73 }, 74 expectedErr: ErrUnexpectedMerkleRoot, 75 }, 76 { 77 name: "block timestamp too far in the future", 78 blockFunc: func(ctrl *gomock.Controller) *Block { 79 mockBlock := block.NewMockBlock(ctrl) 80 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 81 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 82 now := time.Now() 83 tooFarInFutureTime := now.Add(SyncBound + 1) 84 mockBlock.EXPECT().Timestamp().Return(tooFarInFutureTime).AnyTimes() 85 clk := &mockable.Clock{} 86 clk.Set(now) 87 return &Block{ 88 Block: mockBlock, 89 manager: &manager{ 90 backend: defaultTestBackend(false, nil), 91 clk: clk, 92 }, 93 } 94 }, 95 expectedErr: ErrTimestampBeyondSyncBound, 96 }, 97 { 98 name: "block contains no transactions", 99 blockFunc: func(ctrl *gomock.Controller) *Block { 100 mockBlock := block.NewMockBlock(ctrl) 101 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 102 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 103 mockBlock.EXPECT().Timestamp().Return(time.Now()).AnyTimes() 104 mockBlock.EXPECT().Txs().Return(nil).AnyTimes() 105 return &Block{ 106 Block: mockBlock, 107 manager: &manager{ 108 backend: defaultTestBackend(false, nil), 109 blkIDToState: map[ids.ID]*blockState{}, 110 clk: &mockable.Clock{}, 111 }, 112 } 113 }, 114 expectedErr: ErrEmptyBlock, 115 }, 116 { 117 name: "block transaction fails verification", 118 blockFunc: func(ctrl *gomock.Controller) *Block { 119 mockBlock := block.NewMockBlock(ctrl) 120 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 121 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 122 mockBlock.EXPECT().Timestamp().Return(time.Now()).AnyTimes() 123 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 124 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest) 125 errTx := &txs.Tx{ 126 Unsigned: mockUnsignedTx, 127 } 128 mockBlock.EXPECT().Txs().Return([]*txs.Tx{errTx}).AnyTimes() 129 130 mempool := mempoolmock.NewMempool(ctrl) 131 mempool.EXPECT().MarkDropped(errTx.ID(), errTest).Times(1) 132 return &Block{ 133 Block: mockBlock, 134 manager: &manager{ 135 backend: defaultTestBackend(false, nil), 136 mempool: mempool, 137 metrics: metricsmock.NewMetrics(ctrl), 138 blkIDToState: map[ids.ID]*blockState{}, 139 clk: &mockable.Clock{}, 140 }, 141 } 142 }, 143 expectedErr: errTest, 144 }, 145 { 146 name: "parent doesn't exist", 147 blockFunc: func(ctrl *gomock.Controller) *Block { 148 mockBlock := block.NewMockBlock(ctrl) 149 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 150 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 151 mockBlock.EXPECT().Timestamp().Return(time.Now()).AnyTimes() 152 153 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 154 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) 155 tx := &txs.Tx{ 156 Unsigned: mockUnsignedTx, 157 } 158 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 159 160 parentID := ids.GenerateTestID() 161 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 162 163 mockState := statemock.NewState(ctrl) 164 mockState.EXPECT().GetBlock(parentID).Return(nil, errTest) 165 return &Block{ 166 Block: mockBlock, 167 manager: &manager{ 168 backend: defaultTestBackend(false, nil), 169 state: mockState, 170 blkIDToState: map[ids.ID]*blockState{}, 171 clk: &mockable.Clock{}, 172 }, 173 } 174 }, 175 expectedErr: errTest, 176 }, 177 { 178 name: "block height isn't parent height + 1", 179 blockFunc: func(ctrl *gomock.Controller) *Block { 180 mockBlock := block.NewMockBlock(ctrl) 181 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 182 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 183 mockBlock.EXPECT().Timestamp().Return(time.Now()).AnyTimes() 184 blockHeight := uint64(1337) 185 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 186 187 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 188 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) 189 tx := &txs.Tx{ 190 Unsigned: mockUnsignedTx, 191 } 192 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 193 194 parentID := ids.GenerateTestID() 195 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 196 197 mockState := statemock.NewState(ctrl) 198 mockParentBlock := block.NewMockBlock(ctrl) 199 mockParentBlock.EXPECT().Height().Return(blockHeight) // Should be blockHeight - 1 200 mockState.EXPECT().GetBlock(parentID).Return(mockParentBlock, nil) 201 202 return &Block{ 203 Block: mockBlock, 204 manager: &manager{ 205 backend: defaultTestBackend(false, nil), 206 state: mockState, 207 blkIDToState: map[ids.ID]*blockState{}, 208 clk: &mockable.Clock{}, 209 }, 210 } 211 }, 212 expectedErr: ErrIncorrectHeight, 213 }, 214 { 215 name: "block timestamp before parent timestamp", 216 blockFunc: func(ctrl *gomock.Controller) *Block { 217 mockBlock := block.NewMockBlock(ctrl) 218 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 219 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 220 blockTimestamp := time.Now() 221 mockBlock.EXPECT().Timestamp().Return(blockTimestamp).AnyTimes() 222 blockHeight := uint64(1337) 223 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 224 225 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 226 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) 227 tx := &txs.Tx{ 228 Unsigned: mockUnsignedTx, 229 } 230 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 231 232 parentID := ids.GenerateTestID() 233 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 234 235 mockParentBlock := block.NewMockBlock(ctrl) 236 mockParentBlock.EXPECT().Height().Return(blockHeight - 1) 237 238 mockParentState := statemock.NewDiff(ctrl) 239 mockParentState.EXPECT().GetLastAccepted().Return(parentID) 240 mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp.Add(1)) 241 242 return &Block{ 243 Block: mockBlock, 244 manager: &manager{ 245 backend: defaultTestBackend(false, nil), 246 blkIDToState: map[ids.ID]*blockState{ 247 parentID: { 248 onAcceptState: mockParentState, 249 statelessBlock: mockParentBlock, 250 }, 251 }, 252 clk: &mockable.Clock{}, 253 lastAccepted: parentID, 254 }, 255 } 256 }, 257 expectedErr: ErrChildBlockEarlierThanParent, 258 }, 259 { 260 name: "tx fails semantic verification", 261 blockFunc: func(ctrl *gomock.Controller) *Block { 262 mockBlock := block.NewMockBlock(ctrl) 263 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 264 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 265 blockTimestamp := time.Now() 266 mockBlock.EXPECT().Timestamp().Return(blockTimestamp).AnyTimes() 267 blockHeight := uint64(1337) 268 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 269 270 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 271 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Syntactic verification passes 272 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest).Times(1) // Semantic verification fails 273 tx := &txs.Tx{ 274 Unsigned: mockUnsignedTx, 275 } 276 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 277 278 parentID := ids.GenerateTestID() 279 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 280 281 mockParentBlock := block.NewMockBlock(ctrl) 282 mockParentBlock.EXPECT().Height().Return(blockHeight - 1) 283 284 mockParentState := statemock.NewDiff(ctrl) 285 mockParentState.EXPECT().GetLastAccepted().Return(parentID) 286 mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) 287 288 mempool := mempoolmock.NewMempool(ctrl) 289 mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) 290 return &Block{ 291 Block: mockBlock, 292 manager: &manager{ 293 backend: defaultTestBackend(false, nil), 294 mempool: mempool, 295 metrics: metricsmock.NewMetrics(ctrl), 296 blkIDToState: map[ids.ID]*blockState{ 297 parentID: { 298 onAcceptState: mockParentState, 299 statelessBlock: mockParentBlock, 300 }, 301 }, 302 clk: &mockable.Clock{}, 303 lastAccepted: parentID, 304 }, 305 } 306 }, 307 expectedErr: errTest, 308 }, 309 { 310 name: "tx fails execution", 311 blockFunc: func(ctrl *gomock.Controller) *Block { 312 mockBlock := block.NewMockBlock(ctrl) 313 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 314 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 315 blockTimestamp := time.Now() 316 mockBlock.EXPECT().Timestamp().Return(blockTimestamp).AnyTimes() 317 blockHeight := uint64(1337) 318 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 319 320 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 321 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Syntactic verification passes 322 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Semantic verification fails 323 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest).Times(1) // Execution fails 324 tx := &txs.Tx{ 325 Unsigned: mockUnsignedTx, 326 } 327 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 328 329 parentID := ids.GenerateTestID() 330 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 331 332 mockParentBlock := block.NewMockBlock(ctrl) 333 mockParentBlock.EXPECT().Height().Return(blockHeight - 1) 334 335 mockParentState := statemock.NewDiff(ctrl) 336 mockParentState.EXPECT().GetLastAccepted().Return(parentID) 337 mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) 338 339 mempool := mempoolmock.NewMempool(ctrl) 340 mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) 341 return &Block{ 342 Block: mockBlock, 343 manager: &manager{ 344 mempool: mempool, 345 metrics: metricsmock.NewMetrics(ctrl), 346 backend: defaultTestBackend(false, nil), 347 blkIDToState: map[ids.ID]*blockState{ 348 parentID: { 349 onAcceptState: mockParentState, 350 statelessBlock: mockParentBlock, 351 }, 352 }, 353 clk: &mockable.Clock{}, 354 lastAccepted: parentID, 355 }, 356 } 357 }, 358 expectedErr: errTest, 359 }, 360 { 361 name: "tx imported inputs overlap", 362 blockFunc: func(ctrl *gomock.Controller) *Block { 363 mockBlock := block.NewMockBlock(ctrl) 364 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 365 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 366 blockTimestamp := time.Now() 367 mockBlock.EXPECT().Timestamp().Return(blockTimestamp).AnyTimes() 368 blockHeight := uint64(1337) 369 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 370 371 // tx1 and tx2 both consume imported input [inputID] 372 inputID := ids.GenerateTestID() 373 mockUnsignedTx1 := txsmock.NewUnsignedTx(ctrl) 374 mockUnsignedTx1.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Syntactic verification passes 375 mockUnsignedTx1.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Semantic verification fails 376 mockUnsignedTx1.EXPECT().Visit(gomock.Any()).DoAndReturn( 377 func(visitor txs.Visitor) error { 378 executor, ok := visitor.(*executor.Executor) 379 if !ok { 380 return errors.New("wrong visitor type") 381 } 382 executor.Inputs.Add(inputID) 383 return nil 384 }, 385 ).Times(1) 386 mockUnsignedTx2 := txsmock.NewUnsignedTx(ctrl) 387 mockUnsignedTx2.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Syntactic verification passes 388 mockUnsignedTx2.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Semantic verification fails 389 mockUnsignedTx2.EXPECT().Visit(gomock.Any()).DoAndReturn( 390 func(visitor txs.Visitor) error { 391 executor, ok := visitor.(*executor.Executor) 392 if !ok { 393 return errors.New("wrong visitor type") 394 } 395 executor.Inputs.Add(inputID) 396 return nil 397 }, 398 ).Times(1) 399 tx1 := &txs.Tx{ 400 Unsigned: mockUnsignedTx1, 401 } 402 tx2 := &txs.Tx{ 403 Unsigned: mockUnsignedTx2, 404 } 405 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx1, tx2}).AnyTimes() 406 407 parentID := ids.GenerateTestID() 408 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 409 410 mockParentBlock := block.NewMockBlock(ctrl) 411 mockParentBlock.EXPECT().Height().Return(blockHeight - 1) 412 413 mockParentState := statemock.NewDiff(ctrl) 414 mockParentState.EXPECT().GetLastAccepted().Return(parentID) 415 mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) 416 417 mempool := mempoolmock.NewMempool(ctrl) 418 mempool.EXPECT().MarkDropped(tx2.ID(), ErrConflictingBlockTxs).Times(1) 419 return &Block{ 420 Block: mockBlock, 421 manager: &manager{ 422 mempool: mempool, 423 metrics: metricsmock.NewMetrics(ctrl), 424 backend: defaultTestBackend(false, nil), 425 blkIDToState: map[ids.ID]*blockState{ 426 parentID: { 427 onAcceptState: mockParentState, 428 statelessBlock: mockParentBlock, 429 }, 430 }, 431 clk: &mockable.Clock{}, 432 lastAccepted: parentID, 433 }, 434 } 435 }, 436 expectedErr: ErrConflictingBlockTxs, 437 }, 438 { 439 name: "tx input overlaps with other tx", 440 blockFunc: func(ctrl *gomock.Controller) *Block { 441 mockBlock := block.NewMockBlock(ctrl) 442 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 443 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 444 blockTimestamp := time.Now() 445 mockBlock.EXPECT().Timestamp().Return(blockTimestamp).AnyTimes() 446 blockHeight := uint64(1337) 447 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 448 449 // tx1 and parent block both consume [inputID] 450 inputID := ids.GenerateTestID() 451 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 452 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Syntactic verification passes 453 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Semantic verification fails 454 mockUnsignedTx.EXPECT().Visit(gomock.Any()).DoAndReturn( 455 func(visitor txs.Visitor) error { 456 executor, ok := visitor.(*executor.Executor) 457 if !ok { 458 return errors.New("wrong visitor type") 459 } 460 executor.Inputs.Add(inputID) 461 return nil 462 }, 463 ).Times(1) 464 tx := &txs.Tx{ 465 Unsigned: mockUnsignedTx, 466 } 467 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 468 469 parentID := ids.GenerateTestID() 470 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 471 472 mockParentBlock := block.NewMockBlock(ctrl) 473 mockParentBlock.EXPECT().Height().Return(blockHeight - 1) 474 475 mockParentState := statemock.NewDiff(ctrl) 476 mockParentState.EXPECT().GetLastAccepted().Return(parentID) 477 mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) 478 479 return &Block{ 480 Block: mockBlock, 481 manager: &manager{ 482 backend: defaultTestBackend(false, nil), 483 blkIDToState: map[ids.ID]*blockState{ 484 parentID: { 485 onAcceptState: mockParentState, 486 statelessBlock: mockParentBlock, 487 importedInputs: set.Of(inputID), 488 }, 489 }, 490 clk: &mockable.Clock{}, 491 lastAccepted: parentID, 492 }, 493 } 494 }, 495 expectedErr: ErrConflictingParentTxs, 496 }, 497 { 498 name: "happy path", 499 blockFunc: func(ctrl *gomock.Controller) *Block { 500 mockBlock := block.NewMockBlock(ctrl) 501 mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() 502 mockBlock.EXPECT().MerkleRoot().Return(ids.Empty).AnyTimes() 503 blockTimestamp := time.Now() 504 mockBlock.EXPECT().Timestamp().Return(blockTimestamp).AnyTimes() 505 blockHeight := uint64(1337) 506 mockBlock.EXPECT().Height().Return(blockHeight).AnyTimes() 507 508 mockUnsignedTx := txsmock.NewUnsignedTx(ctrl) 509 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Syntactic verification passes 510 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Semantic verification fails 511 mockUnsignedTx.EXPECT().Visit(gomock.Any()).Return(nil).Times(1) // Execution passes 512 tx := &txs.Tx{ 513 Unsigned: mockUnsignedTx, 514 } 515 mockBlock.EXPECT().Txs().Return([]*txs.Tx{tx}).AnyTimes() 516 517 parentID := ids.GenerateTestID() 518 mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() 519 520 mockParentBlock := block.NewMockBlock(ctrl) 521 mockParentBlock.EXPECT().Height().Return(blockHeight - 1) 522 523 mockParentState := statemock.NewDiff(ctrl) 524 mockParentState.EXPECT().GetLastAccepted().Return(parentID) 525 mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) 526 527 mockMempool := mempoolmock.NewMempool(ctrl) 528 mockMempool.EXPECT().Remove([]*txs.Tx{tx}) 529 return &Block{ 530 Block: mockBlock, 531 manager: &manager{ 532 mempool: mockMempool, 533 metrics: metricsmock.NewMetrics(ctrl), 534 backend: defaultTestBackend(false, nil), 535 blkIDToState: map[ids.ID]*blockState{ 536 parentID: { 537 onAcceptState: mockParentState, 538 statelessBlock: mockParentBlock, 539 }, 540 }, 541 clk: &mockable.Clock{}, 542 lastAccepted: parentID, 543 }, 544 } 545 }, 546 expectedErr: nil, 547 postVerify: func(require *require.Assertions, b *Block) { 548 // Assert block is in the cache 549 blockState, ok := b.manager.blkIDToState[b.ID()] 550 require.True(ok) 551 require.Equal(b.Block, blockState.statelessBlock) 552 553 // Assert block is added to on accept state 554 persistedBlock, err := blockState.onAcceptState.GetBlock(b.ID()) 555 require.NoError(err) 556 require.Equal(b.Block, persistedBlock) 557 558 // Assert block is set to last accepted 559 lastAccepted := b.ID() 560 require.Equal(lastAccepted, blockState.onAcceptState.GetLastAccepted()) 561 562 // Assert txs are added to on accept state 563 blockTxs := b.Txs() 564 for _, tx := range blockTxs { 565 _, err := blockState.onAcceptState.GetTx(tx.ID()) 566 require.NoError(err) 567 } 568 }, 569 }, 570 } 571 for _, tt := range tests { 572 t.Run(tt.name, func(t *testing.T) { 573 require := require.New(t) 574 ctrl := gomock.NewController(t) 575 576 b := tt.blockFunc(ctrl) 577 err := b.Verify(context.Background()) 578 require.ErrorIs(err, tt.expectedErr) 579 if tt.postVerify != nil { 580 tt.postVerify(require, b) 581 } 582 }) 583 } 584 } 585 586 func TestBlockAccept(t *testing.T) { 587 type test struct { 588 name string 589 blockFunc func(*gomock.Controller) *Block 590 expectedErr error 591 } 592 tests := []test{ 593 { 594 name: "block not found", 595 blockFunc: func(ctrl *gomock.Controller) *Block { 596 mockBlock := block.NewMockBlock(ctrl) 597 mockBlock.EXPECT().ID().Return(ids.GenerateTestID()).AnyTimes() 598 mockBlock.EXPECT().Txs().Return([]*txs.Tx{}).AnyTimes() 599 600 mempool := mempoolmock.NewMempool(ctrl) 601 mempool.EXPECT().Remove(gomock.Any()).AnyTimes() 602 603 return &Block{ 604 Block: mockBlock, 605 manager: &manager{ 606 mempool: mempool, 607 metrics: metricsmock.NewMetrics(ctrl), 608 backend: defaultTestBackend(false, nil), 609 blkIDToState: map[ids.ID]*blockState{}, 610 }, 611 } 612 }, 613 expectedErr: ErrBlockNotFound, 614 }, 615 { 616 name: "can't get commit batch", 617 blockFunc: func(ctrl *gomock.Controller) *Block { 618 blockID := ids.GenerateTestID() 619 mockBlock := block.NewMockBlock(ctrl) 620 mockBlock.EXPECT().ID().Return(blockID).AnyTimes() 621 mockBlock.EXPECT().Txs().Return([]*txs.Tx{}).AnyTimes() 622 623 mempool := mempoolmock.NewMempool(ctrl) 624 mempool.EXPECT().Remove(gomock.Any()).AnyTimes() 625 626 mockManagerState := statemock.NewState(ctrl) 627 mockManagerState.EXPECT().CommitBatch().Return(nil, errTest) 628 mockManagerState.EXPECT().Abort() 629 630 mockOnAcceptState := statemock.NewDiff(ctrl) 631 mockOnAcceptState.EXPECT().Apply(mockManagerState) 632 633 return &Block{ 634 Block: mockBlock, 635 manager: &manager{ 636 state: mockManagerState, 637 mempool: mempool, 638 backend: defaultTestBackend(false, nil), 639 blkIDToState: map[ids.ID]*blockState{ 640 blockID: { 641 onAcceptState: mockOnAcceptState, 642 }, 643 }, 644 }, 645 } 646 }, 647 expectedErr: errTest, 648 }, 649 { 650 name: "can't apply shared memory", 651 blockFunc: func(ctrl *gomock.Controller) *Block { 652 blockID := ids.GenerateTestID() 653 mockBlock := block.NewMockBlock(ctrl) 654 mockBlock.EXPECT().ID().Return(blockID).AnyTimes() 655 mockBlock.EXPECT().Txs().Return([]*txs.Tx{}).AnyTimes() 656 657 mempool := mempoolmock.NewMempool(ctrl) 658 mempool.EXPECT().Remove(gomock.Any()).AnyTimes() 659 660 mockManagerState := statemock.NewState(ctrl) 661 // Note the returned batch is nil but not used 662 // because we mock the call to shared memory 663 mockManagerState.EXPECT().CommitBatch().Return(nil, nil) 664 mockManagerState.EXPECT().Abort() 665 666 mockSharedMemory := atomicmock.NewSharedMemory(ctrl) 667 mockSharedMemory.EXPECT().Apply(gomock.Any(), gomock.Any()).Return(errTest) 668 669 mockOnAcceptState := statemock.NewDiff(ctrl) 670 mockOnAcceptState.EXPECT().Apply(mockManagerState) 671 672 return &Block{ 673 Block: mockBlock, 674 manager: &manager{ 675 state: mockManagerState, 676 mempool: mempool, 677 backend: defaultTestBackend(false, mockSharedMemory), 678 blkIDToState: map[ids.ID]*blockState{ 679 blockID: { 680 onAcceptState: mockOnAcceptState, 681 }, 682 }, 683 }, 684 } 685 }, 686 expectedErr: errTest, 687 }, 688 { 689 name: "failed to apply metrics", 690 blockFunc: func(ctrl *gomock.Controller) *Block { 691 blockID := ids.GenerateTestID() 692 mockBlock := block.NewMockBlock(ctrl) 693 mockBlock.EXPECT().ID().Return(blockID).AnyTimes() 694 mockBlock.EXPECT().Txs().Return([]*txs.Tx{}).AnyTimes() 695 696 mempool := mempoolmock.NewMempool(ctrl) 697 mempool.EXPECT().Remove(gomock.Any()).AnyTimes() 698 699 mockManagerState := statemock.NewState(ctrl) 700 // Note the returned batch is nil but not used 701 // because we mock the call to shared memory 702 mockManagerState.EXPECT().CommitBatch().Return(nil, nil) 703 mockManagerState.EXPECT().Abort() 704 705 mockSharedMemory := atomicmock.NewSharedMemory(ctrl) 706 mockSharedMemory.EXPECT().Apply(gomock.Any(), gomock.Any()).Return(nil) 707 708 mockOnAcceptState := statemock.NewDiff(ctrl) 709 mockOnAcceptState.EXPECT().Apply(mockManagerState) 710 711 metrics := metricsmock.NewMetrics(ctrl) 712 metrics.EXPECT().MarkBlockAccepted(gomock.Any()).Return(errTest) 713 714 return &Block{ 715 Block: mockBlock, 716 manager: &manager{ 717 state: mockManagerState, 718 mempool: mempool, 719 metrics: metrics, 720 backend: defaultTestBackend(false, mockSharedMemory), 721 blkIDToState: map[ids.ID]*blockState{ 722 blockID: { 723 onAcceptState: mockOnAcceptState, 724 }, 725 }, 726 }, 727 } 728 }, 729 expectedErr: errTest, 730 }, 731 { 732 name: "no error", 733 blockFunc: func(ctrl *gomock.Controller) *Block { 734 blockID := ids.GenerateTestID() 735 mockBlock := block.NewMockBlock(ctrl) 736 mockBlock.EXPECT().ID().Return(blockID).AnyTimes() 737 mockBlock.EXPECT().Height().Return(uint64(0)).AnyTimes() 738 mockBlock.EXPECT().Parent().Return(ids.GenerateTestID()).AnyTimes() 739 mockBlock.EXPECT().Txs().Return([]*txs.Tx{}).AnyTimes() 740 741 mempool := mempoolmock.NewMempool(ctrl) 742 mempool.EXPECT().Remove(gomock.Any()).AnyTimes() 743 744 mockManagerState := statemock.NewState(ctrl) 745 // Note the returned batch is nil but not used 746 // because we mock the call to shared memory 747 mockManagerState.EXPECT().CommitBatch().Return(nil, nil) 748 mockManagerState.EXPECT().Abort() 749 mockManagerState.EXPECT().Checksums().Return(ids.Empty, ids.Empty) 750 751 mockSharedMemory := atomicmock.NewSharedMemory(ctrl) 752 mockSharedMemory.EXPECT().Apply(gomock.Any(), gomock.Any()).Return(nil) 753 754 mockOnAcceptState := statemock.NewDiff(ctrl) 755 mockOnAcceptState.EXPECT().Apply(mockManagerState) 756 757 metrics := metricsmock.NewMetrics(ctrl) 758 metrics.EXPECT().MarkBlockAccepted(gomock.Any()).Return(nil) 759 760 return &Block{ 761 Block: mockBlock, 762 manager: &manager{ 763 state: mockManagerState, 764 mempool: mempool, 765 metrics: metrics, 766 backend: defaultTestBackend(false, mockSharedMemory), 767 blkIDToState: map[ids.ID]*blockState{ 768 blockID: { 769 onAcceptState: mockOnAcceptState, 770 }, 771 }, 772 }, 773 } 774 }, 775 expectedErr: nil, 776 }, 777 } 778 for _, tt := range tests { 779 t.Run(tt.name, func(t *testing.T) { 780 require := require.New(t) 781 ctrl := gomock.NewController(t) 782 783 b := tt.blockFunc(ctrl) 784 err := b.Accept(context.Background()) 785 require.ErrorIs(err, tt.expectedErr) 786 if err == nil { 787 // Make sure block is removed from cache 788 _, ok := b.manager.blkIDToState[b.ID()] 789 require.False(ok) 790 } 791 }) 792 } 793 } 794 795 func TestBlockReject(t *testing.T) { 796 type test struct { 797 name string 798 blockFunc func(*gomock.Controller) *Block 799 } 800 tests := []test{ 801 { 802 name: "one tx passes verification; one fails syntactic verification; one fails semantic verification; one fails execution", 803 blockFunc: func(ctrl *gomock.Controller) *Block { 804 blockID := ids.GenerateTestID() 805 mockBlock := block.NewMockBlock(ctrl) 806 mockBlock.EXPECT().ID().Return(blockID).AnyTimes() 807 mockBlock.EXPECT().Height().Return(uint64(0)).AnyTimes() 808 mockBlock.EXPECT().Parent().Return(ids.GenerateTestID()).AnyTimes() 809 810 unsignedValidTx := txsmock.NewUnsignedTx(ctrl) 811 unsignedValidTx.EXPECT().SetBytes(gomock.Any()) 812 unsignedValidTx.EXPECT().Visit(gomock.Any()).Return(nil).AnyTimes() // Passes verification and execution 813 814 unsignedSyntacticallyInvalidTx := txsmock.NewUnsignedTx(ctrl) 815 unsignedSyntacticallyInvalidTx.EXPECT().SetBytes(gomock.Any()) 816 unsignedSyntacticallyInvalidTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fails syntactic verification 817 818 unsignedSemanticallyInvalidTx := txsmock.NewUnsignedTx(ctrl) 819 unsignedSemanticallyInvalidTx.EXPECT().SetBytes(gomock.Any()) 820 unsignedSemanticallyInvalidTx.EXPECT().Visit(gomock.Any()).Return(nil) // Passes syntactic verification 821 unsignedSemanticallyInvalidTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fails semantic verification 822 823 unsignedExecutionFailsTx := txsmock.NewUnsignedTx(ctrl) 824 unsignedExecutionFailsTx.EXPECT().SetBytes(gomock.Any()) 825 unsignedExecutionFailsTx.EXPECT().Visit(gomock.Any()).Return(nil) // Passes syntactic verification 826 unsignedExecutionFailsTx.EXPECT().Visit(gomock.Any()).Return(nil) // Passes semantic verification 827 unsignedExecutionFailsTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fails execution 828 829 // Give each tx a unique ID 830 validTx := &txs.Tx{Unsigned: unsignedValidTx} 831 validTx.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16)) 832 syntacticallyInvalidTx := &txs.Tx{Unsigned: unsignedSyntacticallyInvalidTx} 833 syntacticallyInvalidTx.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16)) 834 semanticallyInvalidTx := &txs.Tx{Unsigned: unsignedSemanticallyInvalidTx} 835 semanticallyInvalidTx.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16)) 836 executionFailsTx := &txs.Tx{Unsigned: unsignedExecutionFailsTx} 837 executionFailsTx.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16)) 838 839 mockBlock.EXPECT().Txs().Return([]*txs.Tx{ 840 validTx, 841 syntacticallyInvalidTx, 842 semanticallyInvalidTx, 843 executionFailsTx, 844 }) 845 846 mempool := mempoolmock.NewMempool(ctrl) 847 mempool.EXPECT().Add(validTx).Return(nil) // Only add the one that passes verification 848 mempool.EXPECT().RequestBuildBlock() 849 850 lastAcceptedID := ids.GenerateTestID() 851 mockState := statemock.NewState(ctrl) 852 mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() 853 mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() 854 855 return &Block{ 856 Block: mockBlock, 857 manager: &manager{ 858 lastAccepted: lastAcceptedID, 859 mempool: mempool, 860 metrics: metricsmock.NewMetrics(ctrl), 861 backend: defaultTestBackend(true, nil), 862 state: mockState, 863 blkIDToState: map[ids.ID]*blockState{ 864 blockID: {}, 865 }, 866 }, 867 } 868 }, 869 }, 870 { 871 name: "all txs valid", 872 blockFunc: func(ctrl *gomock.Controller) *Block { 873 blockID := ids.GenerateTestID() 874 mockBlock := block.NewMockBlock(ctrl) 875 mockBlock.EXPECT().ID().Return(blockID).AnyTimes() 876 mockBlock.EXPECT().Height().Return(uint64(0)).AnyTimes() 877 mockBlock.EXPECT().Parent().Return(ids.GenerateTestID()).AnyTimes() 878 879 unsignedTx1 := txsmock.NewUnsignedTx(ctrl) 880 unsignedTx1.EXPECT().SetBytes(gomock.Any()) 881 unsignedTx1.EXPECT().Visit(gomock.Any()).Return(nil).AnyTimes() // Passes verification and execution 882 883 unsignedTx2 := txsmock.NewUnsignedTx(ctrl) 884 unsignedTx2.EXPECT().SetBytes(gomock.Any()) 885 unsignedTx2.EXPECT().Visit(gomock.Any()).Return(nil).AnyTimes() // Passes verification and execution 886 887 // Give each tx a unique ID 888 tx1 := &txs.Tx{Unsigned: unsignedTx1} 889 tx1.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16)) 890 tx2 := &txs.Tx{Unsigned: unsignedTx2} 891 tx2.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16)) 892 893 mockBlock.EXPECT().Txs().Return([]*txs.Tx{ 894 tx1, 895 tx2, 896 }) 897 898 mempool := mempoolmock.NewMempool(ctrl) 899 mempool.EXPECT().Add(tx1).Return(nil) 900 mempool.EXPECT().Add(tx2).Return(nil) 901 mempool.EXPECT().RequestBuildBlock() 902 903 lastAcceptedID := ids.GenerateTestID() 904 mockState := statemock.NewState(ctrl) 905 mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() 906 mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() 907 908 return &Block{ 909 Block: mockBlock, 910 manager: &manager{ 911 lastAccepted: lastAcceptedID, 912 mempool: mempool, 913 metrics: metricsmock.NewMetrics(ctrl), 914 backend: defaultTestBackend(true, nil), 915 state: mockState, 916 blkIDToState: map[ids.ID]*blockState{ 917 blockID: {}, 918 }, 919 }, 920 } 921 }, 922 }, 923 } 924 for _, tt := range tests { 925 t.Run(tt.name, func(t *testing.T) { 926 require := require.New(t) 927 ctrl := gomock.NewController(t) 928 929 b := tt.blockFunc(ctrl) 930 require.NoError(b.Reject(context.Background())) 931 _, ok := b.manager.blkIDToState[b.ID()] 932 require.False(ok) 933 }) 934 } 935 } 936 937 func defaultTestBackend(bootstrapped bool, sharedMemory atomic.SharedMemory) *executor.Backend { 938 return &executor.Backend{ 939 Bootstrapped: bootstrapped, 940 Ctx: &snow.Context{ 941 SharedMemory: sharedMemory, 942 Log: logging.NoLog{}, 943 }, 944 Config: &config.Config{ 945 Upgrades: upgradetest.GetConfig(upgradetest.Durango), 946 TxFee: 0, 947 CreateAssetTxFee: 0, 948 }, 949 } 950 }