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