github.com/ava-labs/avalanchego@v1.11.11/vms/avm/block/builder/builder_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 builder
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/stretchr/testify/require"
    14  	"go.uber.org/mock/gomock"
    15  
    16  	"github.com/ava-labs/avalanchego/codec"
    17  	"github.com/ava-labs/avalanchego/codec/codecmock"
    18  	"github.com/ava-labs/avalanchego/database/memdb"
    19  	"github.com/ava-labs/avalanchego/database/versiondb"
    20  	"github.com/ava-labs/avalanchego/ids"
    21  	"github.com/ava-labs/avalanchego/snow"
    22  	"github.com/ava-labs/avalanchego/snow/consensus/snowman"
    23  	"github.com/ava-labs/avalanchego/snow/engine/common"
    24  	"github.com/ava-labs/avalanchego/utils/constants"
    25  	"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
    26  	"github.com/ava-labs/avalanchego/utils/logging"
    27  	"github.com/ava-labs/avalanchego/utils/timer/mockable"
    28  	"github.com/ava-labs/avalanchego/vms/avm/block"
    29  	"github.com/ava-labs/avalanchego/vms/avm/block/executor/executormock"
    30  	"github.com/ava-labs/avalanchego/vms/avm/fxs"
    31  	"github.com/ava-labs/avalanchego/vms/avm/metrics"
    32  	"github.com/ava-labs/avalanchego/vms/avm/state"
    33  	"github.com/ava-labs/avalanchego/vms/avm/state/statemock"
    34  	"github.com/ava-labs/avalanchego/vms/avm/txs"
    35  	"github.com/ava-labs/avalanchego/vms/avm/txs/mempool"
    36  	"github.com/ava-labs/avalanchego/vms/avm/txs/mempool/mempoolmock"
    37  	"github.com/ava-labs/avalanchego/vms/avm/txs/txsmock"
    38  	"github.com/ava-labs/avalanchego/vms/components/avax"
    39  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    40  
    41  	blkexecutor "github.com/ava-labs/avalanchego/vms/avm/block/executor"
    42  	txexecutor "github.com/ava-labs/avalanchego/vms/avm/txs/executor"
    43  )
    44  
    45  const trackChecksums = false
    46  
    47  var (
    48  	errTest = errors.New("test error")
    49  	chainID = ids.GenerateTestID()
    50  	keys    = secp256k1.TestKeys()
    51  )
    52  
    53  func TestBuilderBuildBlock(t *testing.T) {
    54  	type test struct {
    55  		name        string
    56  		builderFunc func(*gomock.Controller) Builder
    57  		expectedErr error
    58  	}
    59  
    60  	tests := []test{
    61  		{
    62  			name: "can't get stateless block",
    63  			builderFunc: func(ctrl *gomock.Controller) Builder {
    64  				preferredID := ids.GenerateTestID()
    65  				manager := executormock.NewManager(ctrl)
    66  				manager.EXPECT().Preferred().Return(preferredID)
    67  				manager.EXPECT().GetStatelessBlock(preferredID).Return(nil, errTest)
    68  
    69  				mempool := mempoolmock.NewMempool(ctrl)
    70  				mempool.EXPECT().RequestBuildBlock()
    71  
    72  				return New(
    73  					&txexecutor.Backend{
    74  						Ctx: &snow.Context{
    75  							Log: logging.NoLog{},
    76  						},
    77  					},
    78  					manager,
    79  					&mockable.Clock{},
    80  					mempool,
    81  				)
    82  			},
    83  			expectedErr: errTest,
    84  		},
    85  		{
    86  			name: "can't get preferred diff",
    87  			builderFunc: func(ctrl *gomock.Controller) Builder {
    88  				preferredID := ids.GenerateTestID()
    89  				preferredHeight := uint64(1337)
    90  				preferredTimestamp := time.Now()
    91  				preferredBlock := block.NewMockBlock(ctrl)
    92  				preferredBlock.EXPECT().Height().Return(preferredHeight)
    93  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
    94  
    95  				manager := executormock.NewManager(ctrl)
    96  				manager.EXPECT().Preferred().Return(preferredID)
    97  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
    98  				manager.EXPECT().GetState(preferredID).Return(nil, false)
    99  
   100  				mempool := mempoolmock.NewMempool(ctrl)
   101  				mempool.EXPECT().RequestBuildBlock()
   102  
   103  				return New(
   104  					&txexecutor.Backend{
   105  						Ctx: &snow.Context{
   106  							Log: logging.NoLog{},
   107  						},
   108  					},
   109  					manager,
   110  					&mockable.Clock{},
   111  					mempool,
   112  				)
   113  			},
   114  			expectedErr: state.ErrMissingParentState,
   115  		},
   116  		{
   117  			name: "tx fails semantic verification",
   118  			builderFunc: func(ctrl *gomock.Controller) Builder {
   119  				preferredID := ids.GenerateTestID()
   120  				preferredHeight := uint64(1337)
   121  				preferredTimestamp := time.Now()
   122  				preferredBlock := block.NewMockBlock(ctrl)
   123  				preferredBlock.EXPECT().Height().Return(preferredHeight)
   124  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
   125  
   126  				preferredState := statemock.NewChain(ctrl)
   127  				preferredState.EXPECT().GetLastAccepted().Return(preferredID)
   128  				preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp)
   129  
   130  				manager := executormock.NewManager(ctrl)
   131  				manager.EXPECT().Preferred().Return(preferredID)
   132  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
   133  				manager.EXPECT().GetState(preferredID).Return(preferredState, true)
   134  
   135  				unsignedTx := txsmock.NewUnsignedTx(ctrl)
   136  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fail semantic verification
   137  				tx := &txs.Tx{Unsigned: unsignedTx}
   138  
   139  				mempool := mempoolmock.NewMempool(ctrl)
   140  				mempool.EXPECT().Peek().Return(tx, true)
   141  				mempool.EXPECT().Remove([]*txs.Tx{tx})
   142  				mempool.EXPECT().MarkDropped(tx.ID(), errTest)
   143  				// Second loop iteration
   144  				mempool.EXPECT().Peek().Return(nil, false)
   145  				mempool.EXPECT().RequestBuildBlock()
   146  
   147  				return New(
   148  					&txexecutor.Backend{
   149  						Ctx: &snow.Context{
   150  							Log: logging.NoLog{},
   151  						},
   152  					},
   153  					manager,
   154  					&mockable.Clock{},
   155  					mempool,
   156  				)
   157  			},
   158  			expectedErr: ErrNoTransactions, // The only tx was invalid
   159  		},
   160  		{
   161  			name: "tx fails execution",
   162  			builderFunc: func(ctrl *gomock.Controller) Builder {
   163  				preferredID := ids.GenerateTestID()
   164  				preferredHeight := uint64(1337)
   165  				preferredTimestamp := time.Now()
   166  				preferredBlock := block.NewMockBlock(ctrl)
   167  				preferredBlock.EXPECT().Height().Return(preferredHeight)
   168  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
   169  
   170  				preferredState := statemock.NewChain(ctrl)
   171  				preferredState.EXPECT().GetLastAccepted().Return(preferredID)
   172  				preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp)
   173  
   174  				manager := executormock.NewManager(ctrl)
   175  				manager.EXPECT().Preferred().Return(preferredID)
   176  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
   177  				manager.EXPECT().GetState(preferredID).Return(preferredState, true)
   178  
   179  				unsignedTx := txsmock.NewUnsignedTx(ctrl)
   180  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil)     // Pass semantic verification
   181  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fail execution
   182  				tx := &txs.Tx{Unsigned: unsignedTx}
   183  
   184  				mempool := mempoolmock.NewMempool(ctrl)
   185  				mempool.EXPECT().Peek().Return(tx, true)
   186  				mempool.EXPECT().Remove([]*txs.Tx{tx})
   187  				mempool.EXPECT().MarkDropped(tx.ID(), errTest)
   188  				// Second loop iteration
   189  				mempool.EXPECT().Peek().Return(nil, false)
   190  				mempool.EXPECT().RequestBuildBlock()
   191  
   192  				return New(
   193  					&txexecutor.Backend{
   194  						Ctx: &snow.Context{
   195  							Log: logging.NoLog{},
   196  						},
   197  					},
   198  					manager,
   199  					&mockable.Clock{},
   200  					mempool,
   201  				)
   202  			},
   203  			expectedErr: ErrNoTransactions, // The only tx was invalid
   204  		},
   205  		{
   206  			name: "tx has non-unique inputs",
   207  			builderFunc: func(ctrl *gomock.Controller) Builder {
   208  				preferredID := ids.GenerateTestID()
   209  				preferredHeight := uint64(1337)
   210  				preferredTimestamp := time.Now()
   211  				preferredBlock := block.NewMockBlock(ctrl)
   212  				preferredBlock.EXPECT().Height().Return(preferredHeight)
   213  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
   214  
   215  				preferredState := statemock.NewChain(ctrl)
   216  				preferredState.EXPECT().GetLastAccepted().Return(preferredID)
   217  				preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp)
   218  
   219  				manager := executormock.NewManager(ctrl)
   220  				manager.EXPECT().Preferred().Return(preferredID)
   221  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
   222  				manager.EXPECT().GetState(preferredID).Return(preferredState, true)
   223  				manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(errTest)
   224  
   225  				unsignedTx := txsmock.NewUnsignedTx(ctrl)
   226  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass semantic verification
   227  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass execution
   228  				tx := &txs.Tx{Unsigned: unsignedTx}
   229  
   230  				mempool := mempoolmock.NewMempool(ctrl)
   231  				mempool.EXPECT().Peek().Return(tx, true)
   232  				mempool.EXPECT().Remove([]*txs.Tx{tx})
   233  				mempool.EXPECT().MarkDropped(tx.ID(), errTest)
   234  				// Second loop iteration
   235  				mempool.EXPECT().Peek().Return(nil, false)
   236  				mempool.EXPECT().RequestBuildBlock()
   237  
   238  				return New(
   239  					&txexecutor.Backend{
   240  						Ctx: &snow.Context{
   241  							Log: logging.NoLog{},
   242  						},
   243  					},
   244  					manager,
   245  					&mockable.Clock{},
   246  					mempool,
   247  				)
   248  			},
   249  			expectedErr: ErrNoTransactions, // The only tx was invalid
   250  		},
   251  		{
   252  			name: "txs consume same input",
   253  			builderFunc: func(ctrl *gomock.Controller) Builder {
   254  				preferredID := ids.GenerateTestID()
   255  				preferredHeight := uint64(1337)
   256  				preferredTimestamp := time.Now()
   257  				preferredBlock := block.NewMockBlock(ctrl)
   258  				preferredBlock.EXPECT().Height().Return(preferredHeight)
   259  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
   260  
   261  				preferredState := statemock.NewChain(ctrl)
   262  				preferredState.EXPECT().GetLastAccepted().Return(preferredID)
   263  				preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp)
   264  
   265  				// tx1 and tx2 both consume [inputID].
   266  				// tx1 is added to the block first, so tx2 should be dropped.
   267  				inputID := ids.GenerateTestID()
   268  				unsignedTx1 := txsmock.NewUnsignedTx(ctrl)
   269  				unsignedTx1.EXPECT().Visit(gomock.Any()).Return(nil)  // Pass semantic verification
   270  				unsignedTx1.EXPECT().Visit(gomock.Any()).DoAndReturn( // Pass execution
   271  					func(visitor txs.Visitor) error {
   272  						require.IsType(t, &txexecutor.Executor{}, visitor)
   273  						executor := visitor.(*txexecutor.Executor)
   274  						executor.Inputs.Add(inputID)
   275  						return nil
   276  					},
   277  				)
   278  				unsignedTx1.EXPECT().SetBytes(gomock.Any()).AnyTimes()
   279  				tx1 := &txs.Tx{Unsigned: unsignedTx1}
   280  				// Set the bytes of tx1 to something other than nil
   281  				// so we can check that the remainingSize is updated
   282  				tx1Bytes := []byte{1, 2, 3}
   283  				tx1.SetBytes(nil, tx1Bytes)
   284  
   285  				unsignedTx2 := txsmock.NewUnsignedTx(ctrl)
   286  				unsignedTx2.EXPECT().Visit(gomock.Any()).Return(nil)  // Pass semantic verification
   287  				unsignedTx2.EXPECT().Visit(gomock.Any()).DoAndReturn( // Pass execution
   288  					func(visitor txs.Visitor) error {
   289  						require.IsType(t, &txexecutor.Executor{}, visitor)
   290  						executor := visitor.(*txexecutor.Executor)
   291  						executor.Inputs.Add(inputID)
   292  						return nil
   293  					},
   294  				)
   295  				tx2 := &txs.Tx{Unsigned: unsignedTx2}
   296  
   297  				manager := executormock.NewManager(ctrl)
   298  				manager.EXPECT().Preferred().Return(preferredID)
   299  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
   300  				manager.EXPECT().GetState(preferredID).Return(preferredState, true)
   301  				manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(nil)
   302  				// Assert created block has one tx, tx1,
   303  				// and other fields are set correctly.
   304  				manager.EXPECT().NewBlock(gomock.Any()).DoAndReturn(
   305  					func(block *block.StandardBlock) snowman.Block {
   306  						require.Len(t, block.Transactions, 1)
   307  						require.Equal(t, tx1, block.Transactions[0])
   308  						require.Equal(t, preferredHeight+1, block.Height())
   309  						require.Equal(t, preferredID, block.Parent())
   310  						return nil
   311  					},
   312  				)
   313  
   314  				mempool := mempoolmock.NewMempool(ctrl)
   315  				mempool.EXPECT().Peek().Return(tx1, true)
   316  				mempool.EXPECT().Remove([]*txs.Tx{tx1})
   317  				// Second loop iteration
   318  				mempool.EXPECT().Peek().Return(tx2, true)
   319  				mempool.EXPECT().Remove([]*txs.Tx{tx2})
   320  				mempool.EXPECT().MarkDropped(tx2.ID(), blkexecutor.ErrConflictingBlockTxs)
   321  				// Third loop iteration
   322  				mempool.EXPECT().Peek().Return(nil, false)
   323  				mempool.EXPECT().RequestBuildBlock()
   324  
   325  				// To marshal the tx/block
   326  				codec := codecmock.NewManager(ctrl)
   327  				codec.EXPECT().Marshal(gomock.Any(), gomock.Any()).Return([]byte{1, 2, 3}, nil).AnyTimes()
   328  				codec.EXPECT().Size(gomock.Any(), gomock.Any()).Return(2, nil).AnyTimes()
   329  
   330  				return New(
   331  					&txexecutor.Backend{
   332  						Codec: codec,
   333  						Ctx: &snow.Context{
   334  							Log: logging.NoLog{},
   335  						},
   336  					},
   337  					manager,
   338  					&mockable.Clock{},
   339  					mempool,
   340  				)
   341  			},
   342  			expectedErr: nil,
   343  		},
   344  		{
   345  			name: "preferred timestamp after now",
   346  			builderFunc: func(ctrl *gomock.Controller) Builder {
   347  				preferredID := ids.GenerateTestID()
   348  				preferredHeight := uint64(1337)
   349  				preferredTimestamp := time.Now()
   350  				preferredBlock := block.NewMockBlock(ctrl)
   351  				preferredBlock.EXPECT().Height().Return(preferredHeight)
   352  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
   353  
   354  				// Clock reads just before the preferred timestamp.
   355  				// Created block should have the preferred timestamp since it's later.
   356  				clock := &mockable.Clock{}
   357  				clock.Set(preferredTimestamp.Add(-2 * time.Second))
   358  
   359  				preferredState := statemock.NewChain(ctrl)
   360  				preferredState.EXPECT().GetLastAccepted().Return(preferredID)
   361  				preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp)
   362  
   363  				manager := executormock.NewManager(ctrl)
   364  				manager.EXPECT().Preferred().Return(preferredID)
   365  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
   366  				manager.EXPECT().GetState(preferredID).Return(preferredState, true)
   367  				manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(nil)
   368  				// Assert that the created block has the right timestamp
   369  				manager.EXPECT().NewBlock(gomock.Any()).DoAndReturn(
   370  					func(block *block.StandardBlock) snowman.Block {
   371  						require.Equal(t, preferredTimestamp.Unix(), block.Timestamp().Unix())
   372  						return nil
   373  					},
   374  				)
   375  
   376  				inputID := ids.GenerateTestID()
   377  				unsignedTx := txsmock.NewUnsignedTx(ctrl)
   378  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil)  // Pass semantic verification
   379  				unsignedTx.EXPECT().Visit(gomock.Any()).DoAndReturn( // Pass execution
   380  					func(visitor txs.Visitor) error {
   381  						require.IsType(t, &txexecutor.Executor{}, visitor)
   382  						executor := visitor.(*txexecutor.Executor)
   383  						executor.Inputs.Add(inputID)
   384  						return nil
   385  					},
   386  				)
   387  				unsignedTx.EXPECT().SetBytes(gomock.Any()).AnyTimes()
   388  				tx := &txs.Tx{Unsigned: unsignedTx}
   389  
   390  				mempool := mempoolmock.NewMempool(ctrl)
   391  				mempool.EXPECT().Peek().Return(tx, true)
   392  				mempool.EXPECT().Remove([]*txs.Tx{tx})
   393  				// Second loop iteration
   394  				mempool.EXPECT().Peek().Return(nil, false)
   395  				mempool.EXPECT().RequestBuildBlock()
   396  
   397  				// To marshal the tx/block
   398  				codec := codecmock.NewManager(ctrl)
   399  				codec.EXPECT().Marshal(gomock.Any(), gomock.Any()).Return([]byte{1, 2, 3}, nil).AnyTimes()
   400  				codec.EXPECT().Size(gomock.Any(), gomock.Any()).Return(2, nil).AnyTimes()
   401  
   402  				return New(
   403  					&txexecutor.Backend{
   404  						Codec: codec,
   405  						Ctx: &snow.Context{
   406  							Log: logging.NoLog{},
   407  						},
   408  					},
   409  					manager,
   410  					clock,
   411  					mempool,
   412  				)
   413  			},
   414  			expectedErr: nil,
   415  		},
   416  		{
   417  			name: "preferred timestamp before now",
   418  			builderFunc: func(ctrl *gomock.Controller) Builder {
   419  				preferredID := ids.GenerateTestID()
   420  				preferredHeight := uint64(1337)
   421  				// preferred block's timestamp is after the time reported by clock
   422  				now := time.Now()
   423  				preferredTimestamp := now.Add(-2 * time.Second)
   424  				preferredBlock := block.NewMockBlock(ctrl)
   425  				preferredBlock.EXPECT().Height().Return(preferredHeight)
   426  				preferredBlock.EXPECT().Timestamp().Return(preferredTimestamp)
   427  
   428  				// Clock reads after the preferred timestamp.
   429  				// Created block should have [now] timestamp since it's later.
   430  				clock := &mockable.Clock{}
   431  				clock.Set(now)
   432  
   433  				preferredState := statemock.NewChain(ctrl)
   434  				preferredState.EXPECT().GetLastAccepted().Return(preferredID)
   435  				preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp)
   436  
   437  				manager := executormock.NewManager(ctrl)
   438  				manager.EXPECT().Preferred().Return(preferredID)
   439  				manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil)
   440  				manager.EXPECT().GetState(preferredID).Return(preferredState, true)
   441  				manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(nil)
   442  				// Assert that the created block has the right timestamp
   443  				manager.EXPECT().NewBlock(gomock.Any()).DoAndReturn(
   444  					func(block *block.StandardBlock) snowman.Block {
   445  						require.Equal(t, now.Unix(), block.Timestamp().Unix())
   446  						return nil
   447  					},
   448  				)
   449  
   450  				inputID := ids.GenerateTestID()
   451  				unsignedTx := txsmock.NewUnsignedTx(ctrl)
   452  				unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil)  // Pass semantic verification
   453  				unsignedTx.EXPECT().Visit(gomock.Any()).DoAndReturn( // Pass execution
   454  					func(visitor txs.Visitor) error {
   455  						require.IsType(t, &txexecutor.Executor{}, visitor)
   456  						executor := visitor.(*txexecutor.Executor)
   457  						executor.Inputs.Add(inputID)
   458  						return nil
   459  					},
   460  				)
   461  				unsignedTx.EXPECT().SetBytes(gomock.Any()).AnyTimes()
   462  				tx := &txs.Tx{Unsigned: unsignedTx}
   463  
   464  				mempool := mempoolmock.NewMempool(ctrl)
   465  				mempool.EXPECT().Peek().Return(tx, true)
   466  				mempool.EXPECT().Remove([]*txs.Tx{tx})
   467  				// Second loop iteration
   468  				mempool.EXPECT().Peek().Return(nil, false)
   469  				mempool.EXPECT().RequestBuildBlock()
   470  
   471  				// To marshal the tx/block
   472  				codec := codecmock.NewManager(ctrl)
   473  				codec.EXPECT().Marshal(gomock.Any(), gomock.Any()).Return([]byte{1, 2, 3}, nil).AnyTimes()
   474  				codec.EXPECT().Size(gomock.Any(), gomock.Any()).Return(2, nil).AnyTimes()
   475  
   476  				return New(
   477  					&txexecutor.Backend{
   478  						Codec: codec,
   479  						Ctx: &snow.Context{
   480  							Log: logging.NoLog{},
   481  						},
   482  					},
   483  					manager,
   484  					clock,
   485  					mempool,
   486  				)
   487  			},
   488  			expectedErr: nil,
   489  		},
   490  	}
   491  
   492  	for _, tt := range tests {
   493  		t.Run(tt.name, func(t *testing.T) {
   494  			ctrl := gomock.NewController(t)
   495  
   496  			builder := tt.builderFunc(ctrl)
   497  			_, err := builder.BuildBlock(context.Background())
   498  			require.ErrorIs(t, err, tt.expectedErr)
   499  		})
   500  	}
   501  }
   502  
   503  func TestBlockBuilderAddLocalTx(t *testing.T) {
   504  	transactions := createTxs()
   505  
   506  	require := require.New(t)
   507  
   508  	registerer := prometheus.NewRegistry()
   509  	toEngine := make(chan common.Message, 100)
   510  	mempool, err := mempool.New("mempool", registerer, toEngine)
   511  	require.NoError(err)
   512  	// add a tx to the mempool
   513  	tx := transactions[0]
   514  	txID := tx.ID()
   515  	require.NoError(mempool.Add(tx))
   516  
   517  	_, ok := mempool.Get(txID)
   518  	require.True(ok)
   519  
   520  	parser, err := block.NewParser(
   521  		[]fxs.Fx{
   522  			&secp256k1fx.Fx{},
   523  		},
   524  	)
   525  	require.NoError(err)
   526  
   527  	backend := &txexecutor.Backend{
   528  		Ctx: &snow.Context{
   529  			Log: logging.NoLog{},
   530  		},
   531  		Codec: parser.Codec(),
   532  	}
   533  
   534  	baseDB := versiondb.New(memdb.New())
   535  
   536  	state, err := state.New(baseDB, parser, registerer, trackChecksums)
   537  	require.NoError(err)
   538  
   539  	clk := &mockable.Clock{}
   540  	onAccept := func(*txs.Tx) error { return nil }
   541  	now := time.Now()
   542  	parentTimestamp := now.Add(-2 * time.Second)
   543  	parentID := ids.GenerateTestID()
   544  	cm := parser.Codec()
   545  	txs, err := createParentTxs(cm)
   546  	require.NoError(err)
   547  	parentBlk, err := block.NewStandardBlock(parentID, 0, parentTimestamp, txs, cm)
   548  	require.NoError(err)
   549  	state.AddBlock(parentBlk)
   550  	state.SetLastAccepted(parentBlk.ID())
   551  
   552  	metrics, err := metrics.New(registerer)
   553  	require.NoError(err)
   554  
   555  	manager := blkexecutor.NewManager(mempool, metrics, state, backend, clk, onAccept)
   556  
   557  	manager.SetPreference(parentBlk.ID())
   558  
   559  	builder := New(backend, manager, clk, mempool)
   560  
   561  	// show that build block fails if tx is invalid
   562  	_, err = builder.BuildBlock(context.Background())
   563  	require.ErrorIs(err, ErrNoTransactions)
   564  }
   565  
   566  func createTxs() []*txs.Tx {
   567  	return []*txs.Tx{{
   568  		Unsigned: &txs.BaseTx{BaseTx: avax.BaseTx{
   569  			NetworkID:    constants.UnitTestID,
   570  			BlockchainID: ids.GenerateTestID(),
   571  			Outs: []*avax.TransferableOutput{{
   572  				Asset: avax.Asset{ID: ids.GenerateTestID()},
   573  				Out: &secp256k1fx.TransferOutput{
   574  					OutputOwners: secp256k1fx.OutputOwners{
   575  						Addrs: []ids.ShortID{ids.GenerateTestShortID()},
   576  					},
   577  				},
   578  			}},
   579  			Ins: []*avax.TransferableInput{{
   580  				UTXOID: avax.UTXOID{
   581  					TxID:        ids.ID{'t', 'x', 'I', 'D'},
   582  					OutputIndex: 1,
   583  				},
   584  				Asset: avax.Asset{ID: ids.GenerateTestID()},
   585  				In: &secp256k1fx.TransferInput{
   586  					Amt: uint64(54321),
   587  					Input: secp256k1fx.Input{
   588  						SigIndices: []uint32{2},
   589  					},
   590  				},
   591  			}},
   592  			Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8},
   593  		}},
   594  		Creds: []*fxs.FxCredential{
   595  			{
   596  				Credential: &secp256k1fx.Credential{},
   597  			},
   598  		},
   599  	}}
   600  }
   601  
   602  func createParentTxs(cm codec.Manager) ([]*txs.Tx, error) {
   603  	countTxs := 1
   604  	testTxs := make([]*txs.Tx, 0, countTxs)
   605  	for i := 0; i < countTxs; i++ {
   606  		// Create the tx
   607  		tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: avax.BaseTx{
   608  			NetworkID:    constants.UnitTestID,
   609  			BlockchainID: chainID,
   610  			Outs: []*avax.TransferableOutput{{
   611  				Asset: avax.Asset{ID: ids.ID{1, 2, 3}},
   612  				Out: &secp256k1fx.TransferOutput{
   613  					Amt: uint64(12345),
   614  					OutputOwners: secp256k1fx.OutputOwners{
   615  						Threshold: 1,
   616  						Addrs:     []ids.ShortID{keys[0].PublicKey().Address()},
   617  					},
   618  				},
   619  			}},
   620  			Ins: []*avax.TransferableInput{{
   621  				UTXOID: avax.UTXOID{
   622  					TxID:        ids.ID{'t', 'x', 'p', 'a', 'r', 'e', 'n', 't'},
   623  					OutputIndex: 1,
   624  				},
   625  				Asset: avax.Asset{ID: ids.ID{1, 2, 3}},
   626  				In: &secp256k1fx.TransferInput{
   627  					Amt: uint64(54321),
   628  					Input: secp256k1fx.Input{
   629  						SigIndices: []uint32{2},
   630  					},
   631  				},
   632  			}},
   633  			Memo: []byte{1, 2, 9, 4, 5, 6, 7, 8},
   634  		}}}
   635  		if err := tx.SignSECP256K1Fx(cm, [][]*secp256k1.PrivateKey{{keys[0]}}); err != nil {
   636  			return nil, err
   637  		}
   638  		testTxs = append(testTxs, tx)
   639  	}
   640  	return testTxs, nil
   641  }