github.com/ava-labs/avalanchego@v1.11.11/vms/avm/block/executor/manager_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  	"errors"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/require"
    12  	"go.uber.org/mock/gomock"
    13  
    14  	"github.com/ava-labs/avalanchego/ids"
    15  	"github.com/ava-labs/avalanchego/utils/set"
    16  	"github.com/ava-labs/avalanchego/vms/avm/block"
    17  	"github.com/ava-labs/avalanchego/vms/avm/state/statemock"
    18  	"github.com/ava-labs/avalanchego/vms/avm/txs"
    19  	"github.com/ava-labs/avalanchego/vms/avm/txs/txsmock"
    20  )
    21  
    22  var (
    23  	errTest                    = errors.New("test error")
    24  	errTestSyntacticVerifyFail = errors.New("test error")
    25  	errTestSemanticVerifyFail  = errors.New("test error")
    26  	errTestExecutionFail       = errors.New("test error")
    27  )
    28  
    29  func TestManagerGetStatelessBlock(t *testing.T) {
    30  	require := require.New(t)
    31  	ctrl := gomock.NewController(t)
    32  
    33  	state := statemock.NewState(ctrl)
    34  	m := &manager{
    35  		state:        state,
    36  		blkIDToState: map[ids.ID]*blockState{},
    37  	}
    38  
    39  	// Case: block is in memory
    40  	{
    41  		statelessBlk := block.NewMockBlock(ctrl)
    42  		blkID := ids.GenerateTestID()
    43  		blk := &blockState{
    44  			statelessBlock: statelessBlk,
    45  		}
    46  		m.blkIDToState[blkID] = blk
    47  		gotBlk, err := m.GetStatelessBlock(blkID)
    48  		require.NoError(err)
    49  		require.Equal(statelessBlk, gotBlk)
    50  	}
    51  
    52  	// Case: block isn't in memory
    53  	{
    54  		blkID := ids.GenerateTestID()
    55  		blk := block.NewMockBlock(ctrl)
    56  		state.EXPECT().GetBlock(blkID).Return(blk, nil)
    57  		gotBlk, err := m.GetStatelessBlock(blkID)
    58  		require.NoError(err)
    59  		require.Equal(blk, gotBlk)
    60  	}
    61  
    62  	// Case: error while getting block from state
    63  	{
    64  		blkID := ids.GenerateTestID()
    65  		state.EXPECT().GetBlock(blkID).Return(nil, errTest)
    66  		_, err := m.GetStatelessBlock(blkID)
    67  		require.ErrorIs(err, errTest)
    68  	}
    69  }
    70  
    71  func TestManagerGetState(t *testing.T) {
    72  	require := require.New(t)
    73  	ctrl := gomock.NewController(t)
    74  
    75  	s := statemock.NewState(ctrl)
    76  	m := &manager{
    77  		state:        s,
    78  		blkIDToState: map[ids.ID]*blockState{},
    79  		lastAccepted: ids.GenerateTestID(),
    80  	}
    81  
    82  	// Case: Block is in memory
    83  	{
    84  		diff := statemock.NewDiff(ctrl)
    85  		blkID := ids.GenerateTestID()
    86  		m.blkIDToState[blkID] = &blockState{
    87  			onAcceptState: diff,
    88  		}
    89  		gotState, ok := m.GetState(blkID)
    90  		require.True(ok)
    91  		require.Equal(diff, gotState)
    92  	}
    93  
    94  	// Case: Block isn't in memory; block isn't last accepted
    95  	{
    96  		blkID := ids.GenerateTestID()
    97  		gotState, ok := m.GetState(blkID)
    98  		require.False(ok)
    99  		require.Equal(s, gotState)
   100  	}
   101  
   102  	// Case: Block isn't in memory; block is last accepted
   103  	{
   104  		gotState, ok := m.GetState(m.lastAccepted)
   105  		require.True(ok)
   106  		require.Equal(s, gotState)
   107  	}
   108  }
   109  
   110  func TestManagerVerifyTx(t *testing.T) {
   111  	type test struct {
   112  		name        string
   113  		txF         func(*gomock.Controller) *txs.Tx
   114  		managerF    func(*gomock.Controller) *manager
   115  		expectedErr error
   116  	}
   117  
   118  	tests := []test{
   119  		{
   120  			name: "not bootstrapped",
   121  			txF: func(*gomock.Controller) *txs.Tx {
   122  				return &txs.Tx{}
   123  			},
   124  			managerF: func(*gomock.Controller) *manager {
   125  				return &manager{
   126  					backend: defaultTestBackend(false, nil),
   127  				}
   128  			},
   129  			expectedErr: ErrChainNotSynced,
   130  		},
   131  		{
   132  			name: "fails syntactic verification",
   133  			txF: func(ctrl *gomock.Controller) *txs.Tx {
   134  				unsigned := txsmock.NewUnsignedTx(ctrl)
   135  				unsigned.EXPECT().Visit(gomock.Any()).Return(errTestSyntacticVerifyFail)
   136  				return &txs.Tx{
   137  					Unsigned: unsigned,
   138  				}
   139  			},
   140  			managerF: func(*gomock.Controller) *manager {
   141  				return &manager{
   142  					backend: defaultTestBackend(true, nil),
   143  				}
   144  			},
   145  			expectedErr: errTestSyntacticVerifyFail,
   146  		},
   147  		{
   148  			name: "fails semantic verification",
   149  			txF: func(ctrl *gomock.Controller) *txs.Tx {
   150  				unsigned := txsmock.NewUnsignedTx(ctrl)
   151  				// Syntactic verification passes
   152  				unsigned.EXPECT().Visit(gomock.Any()).Return(nil)
   153  				// Semantic verification fails
   154  				unsigned.EXPECT().Visit(gomock.Any()).Return(errTestSemanticVerifyFail)
   155  				return &txs.Tx{
   156  					Unsigned: unsigned,
   157  				}
   158  			},
   159  			managerF: func(ctrl *gomock.Controller) *manager {
   160  				lastAcceptedID := ids.GenerateTestID()
   161  
   162  				// These values don't matter for this test
   163  				state := statemock.NewState(ctrl)
   164  				state.EXPECT().GetLastAccepted().Return(lastAcceptedID)
   165  				state.EXPECT().GetTimestamp().Return(time.Time{})
   166  
   167  				return &manager{
   168  					backend:      defaultTestBackend(true, nil),
   169  					state:        state,
   170  					lastAccepted: lastAcceptedID,
   171  				}
   172  			},
   173  			expectedErr: errTestSemanticVerifyFail,
   174  		},
   175  		{
   176  			name: "fails execution",
   177  			txF: func(ctrl *gomock.Controller) *txs.Tx {
   178  				unsigned := txsmock.NewUnsignedTx(ctrl)
   179  				// Syntactic verification passes
   180  				unsigned.EXPECT().Visit(gomock.Any()).Return(nil)
   181  				// Semantic verification passes
   182  				unsigned.EXPECT().Visit(gomock.Any()).Return(nil)
   183  				// Execution fails
   184  				unsigned.EXPECT().Visit(gomock.Any()).Return(errTestExecutionFail)
   185  				return &txs.Tx{
   186  					Unsigned: unsigned,
   187  				}
   188  			},
   189  			managerF: func(ctrl *gomock.Controller) *manager {
   190  				lastAcceptedID := ids.GenerateTestID()
   191  
   192  				// These values don't matter for this test
   193  				state := statemock.NewState(ctrl)
   194  				state.EXPECT().GetLastAccepted().Return(lastAcceptedID)
   195  				state.EXPECT().GetTimestamp().Return(time.Time{})
   196  
   197  				return &manager{
   198  					backend:      defaultTestBackend(true, nil),
   199  					state:        state,
   200  					lastAccepted: lastAcceptedID,
   201  				}
   202  			},
   203  			expectedErr: errTestExecutionFail,
   204  		},
   205  		{
   206  			name: "happy path",
   207  			txF: func(ctrl *gomock.Controller) *txs.Tx {
   208  				unsigned := txsmock.NewUnsignedTx(ctrl)
   209  				// Syntactic verification passes
   210  				unsigned.EXPECT().Visit(gomock.Any()).Return(nil)
   211  				// Semantic verification passes
   212  				unsigned.EXPECT().Visit(gomock.Any()).Return(nil)
   213  				// Execution passes
   214  				unsigned.EXPECT().Visit(gomock.Any()).Return(nil)
   215  				return &txs.Tx{
   216  					Unsigned: unsigned,
   217  				}
   218  			},
   219  			managerF: func(ctrl *gomock.Controller) *manager {
   220  				lastAcceptedID := ids.GenerateTestID()
   221  
   222  				// These values don't matter for this test
   223  				state := statemock.NewState(ctrl)
   224  				state.EXPECT().GetLastAccepted().Return(lastAcceptedID)
   225  				state.EXPECT().GetTimestamp().Return(time.Time{})
   226  
   227  				return &manager{
   228  					backend:      defaultTestBackend(true, nil),
   229  					state:        state,
   230  					lastAccepted: lastAcceptedID,
   231  				}
   232  			},
   233  			expectedErr: nil,
   234  		},
   235  	}
   236  
   237  	for _, test := range tests {
   238  		t.Run(test.name, func(t *testing.T) {
   239  			require := require.New(t)
   240  			ctrl := gomock.NewController(t)
   241  
   242  			m := test.managerF(ctrl)
   243  			tx := test.txF(ctrl)
   244  			err := m.VerifyTx(tx)
   245  			require.ErrorIs(err, test.expectedErr)
   246  		})
   247  	}
   248  }
   249  
   250  func TestVerifyUniqueInputs(t *testing.T) {
   251  	require := require.New(t)
   252  	ctrl := gomock.NewController(t)
   253  
   254  	// Case: No inputs
   255  	{
   256  		m := &manager{}
   257  		require.NoError(m.VerifyUniqueInputs(ids.GenerateTestID(), set.Set[ids.ID]{}))
   258  	}
   259  
   260  	// blk0 is blk1's parent
   261  	blk0ID, blk1ID := ids.GenerateTestID(), ids.GenerateTestID()
   262  	blk0, blk1 := block.NewMockBlock(ctrl), block.NewMockBlock(ctrl)
   263  	blk1.EXPECT().Parent().Return(blk0ID).AnyTimes()
   264  	blk0.EXPECT().Parent().Return(ids.Empty).AnyTimes() // blk0's parent is accepted
   265  
   266  	inputID := ids.GenerateTestID()
   267  	m := &manager{
   268  		blkIDToState: map[ids.ID]*blockState{
   269  			blk0ID: {
   270  				statelessBlock: blk0,
   271  				importedInputs: set.Of(inputID),
   272  			},
   273  			blk1ID: {
   274  				statelessBlock: blk1,
   275  				importedInputs: set.Of(ids.GenerateTestID()),
   276  			},
   277  		},
   278  	}
   279  	// [blk1]'s parent, [blk0], has [inputID] as an input
   280  	err := m.VerifyUniqueInputs(blk1ID, set.Of(inputID))
   281  	require.ErrorIs(err, ErrConflictingParentTxs)
   282  
   283  	require.NoError(m.VerifyUniqueInputs(blk1ID, set.Of(ids.GenerateTestID())))
   284  }