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  }