github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/snowman/transitive_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 snowman
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/prometheus/client_golang/prometheus"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/MetalBlockchain/metalgo/cache"
    18  	"github.com/MetalBlockchain/metalgo/database"
    19  	"github.com/MetalBlockchain/metalgo/ids"
    20  	"github.com/MetalBlockchain/metalgo/snow"
    21  	"github.com/MetalBlockchain/metalgo/snow/choices"
    22  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowball"
    23  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman"
    24  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman/snowmantest"
    25  	"github.com/MetalBlockchain/metalgo/snow/engine/common"
    26  	"github.com/MetalBlockchain/metalgo/snow/engine/snowman/ancestor"
    27  	"github.com/MetalBlockchain/metalgo/snow/engine/snowman/block"
    28  	"github.com/MetalBlockchain/metalgo/snow/engine/snowman/getter"
    29  	"github.com/MetalBlockchain/metalgo/snow/snowtest"
    30  	"github.com/MetalBlockchain/metalgo/snow/validators"
    31  	"github.com/MetalBlockchain/metalgo/utils/set"
    32  	"github.com/MetalBlockchain/metalgo/version"
    33  )
    34  
    35  var (
    36  	errUnknownBlock = errors.New("unknown block")
    37  	errUnknownBytes = errors.New("unknown bytes")
    38  	errInvalid      = errors.New("invalid")
    39  	errTest         = errors.New("non-nil test")
    40  )
    41  
    42  func MakeGetBlockF(blks ...[]*snowmantest.Block) func(context.Context, ids.ID) (snowman.Block, error) {
    43  	return func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
    44  		for _, blkSet := range blks {
    45  			for _, blk := range blkSet {
    46  				if blkID == blk.ID() {
    47  					return blk, nil
    48  				}
    49  			}
    50  		}
    51  		return nil, errUnknownBlock
    52  	}
    53  }
    54  
    55  func MakeParseBlockF(blks ...[]*snowmantest.Block) func(context.Context, []byte) (snowman.Block, error) {
    56  	return func(_ context.Context, blkBytes []byte) (snowman.Block, error) {
    57  		for _, blkSet := range blks {
    58  			for _, blk := range blkSet {
    59  				if bytes.Equal(blkBytes, blk.Bytes()) {
    60  					return blk, nil
    61  				}
    62  			}
    63  		}
    64  		return nil, errUnknownBlock
    65  	}
    66  }
    67  
    68  func MakeLastAcceptedBlockF(defaultBlk *snowmantest.Block, blks ...[]*snowmantest.Block) func(context.Context) (ids.ID, error) {
    69  	return func(_ context.Context) (ids.ID, error) {
    70  		highestHeight := defaultBlk.Height()
    71  		highestID := defaultBlk.ID()
    72  		for _, blkSet := range blks {
    73  			for _, blk := range blkSet {
    74  				if blk.Status() == choices.Accepted && blk.Height() > highestHeight {
    75  					highestHeight = blk.Height()
    76  					highestID = blk.ID()
    77  				}
    78  			}
    79  		}
    80  		return highestID, nil
    81  	}
    82  }
    83  
    84  func setup(t *testing.T, config Config) (ids.NodeID, validators.Manager, *common.SenderTest, *block.TestVM, *Transitive) {
    85  	require := require.New(t)
    86  
    87  	vdr := ids.GenerateTestNodeID()
    88  	require.NoError(config.Validators.AddStaker(config.Ctx.SubnetID, vdr, nil, ids.Empty, 1))
    89  	require.NoError(config.ConnectedValidators.Connected(context.Background(), vdr, version.CurrentApp))
    90  	config.Validators.RegisterSetCallbackListener(config.Ctx.SubnetID, config.ConnectedValidators)
    91  
    92  	sender := &common.SenderTest{T: t}
    93  	config.Sender = sender
    94  	sender.Default(true)
    95  
    96  	vm := &block.TestVM{}
    97  	vm.T = t
    98  	config.VM = vm
    99  
   100  	snowGetHandler, err := getter.New(
   101  		vm,
   102  		sender,
   103  		config.Ctx.Log,
   104  		time.Second,
   105  		2000,
   106  		config.Ctx.Registerer,
   107  	)
   108  	require.NoError(err)
   109  	config.AllGetsServer = snowGetHandler
   110  
   111  	vm.Default(true)
   112  	vm.CantSetState = false
   113  	vm.CantSetPreference = false
   114  
   115  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
   116  		return snowmantest.GenesisID, nil
   117  	}
   118  
   119  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   120  		switch blkID {
   121  		case snowmantest.GenesisID:
   122  			return snowmantest.Genesis, nil
   123  		default:
   124  			return nil, errUnknownBlock
   125  		}
   126  	}
   127  
   128  	te, err := New(config)
   129  	require.NoError(err)
   130  
   131  	require.NoError(te.Start(context.Background(), 0))
   132  
   133  	vm.GetBlockF = nil
   134  	vm.LastAcceptedF = nil
   135  	return vdr, config.Validators, sender, vm, te
   136  }
   137  
   138  func TestEngineDropsAttemptToIssueBlockAfterFailedRequest(t *testing.T) {
   139  	require := require.New(t)
   140  
   141  	peerID, _, sender, vm, engine := setup(t, DefaultConfig(t))
   142  
   143  	parent := snowmantest.BuildChild(snowmantest.Genesis)
   144  	child := snowmantest.BuildChild(parent)
   145  
   146  	var request *common.Request
   147  	sender.SendGetF = func(_ context.Context, nodeID ids.NodeID, requestID uint32, blkID ids.ID) {
   148  		require.Nil(request)
   149  		request = &common.Request{
   150  			NodeID:    nodeID,
   151  			RequestID: requestID,
   152  		}
   153  		require.Equal(parent.ID(), blkID)
   154  	}
   155  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   156  		require.Equal(child.Bytes(), b)
   157  		return child, nil
   158  	}
   159  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   160  		switch blkID {
   161  		case snowmantest.GenesisID:
   162  			return snowmantest.Genesis, nil
   163  		default:
   164  			return nil, errUnknownBlock
   165  		}
   166  	}
   167  
   168  	// Attempting to add [child] will cause [parent] to be requested. While the
   169  	// request for [parent] is outstanding, [child] will be registered into a
   170  	// job blocked on [parent]'s issuance.
   171  	require.NoError(engine.Put(context.Background(), peerID, 0, child.Bytes()))
   172  	require.NotNil(request)
   173  	require.Equal(1, engine.blocked.NumDependencies())
   174  
   175  	vm.ParseBlockF = func(context.Context, []byte) (snowman.Block, error) {
   176  		return nil, errUnknownBytes
   177  	}
   178  
   179  	// Because this request doesn't provide [parent], the [child] job should be
   180  	// cancelled.
   181  	require.NoError(engine.Put(context.Background(), request.NodeID, request.RequestID, nil))
   182  	require.Zero(engine.blocked.NumDependencies())
   183  }
   184  
   185  func TestEngineQuery(t *testing.T) {
   186  	require := require.New(t)
   187  
   188  	peerID, _, sender, vm, engine := setup(t, DefaultConfig(t))
   189  
   190  	parent := snowmantest.BuildChild(snowmantest.Genesis)
   191  	child := snowmantest.BuildChild(parent)
   192  
   193  	var sendChitsCalled bool
   194  	sender.SendChitsF = func(_ context.Context, _ ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDByHeight ids.ID, accepted ids.ID) {
   195  		require.False(sendChitsCalled)
   196  		sendChitsCalled = true
   197  		require.Equal(uint32(15), requestID)
   198  		require.Equal(snowmantest.GenesisID, preferredID)
   199  		require.Equal(snowmantest.GenesisID, preferredIDByHeight)
   200  		require.Equal(snowmantest.GenesisID, accepted)
   201  	}
   202  
   203  	var getBlockCalled bool
   204  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   205  		getBlockCalled = true
   206  
   207  		switch blkID {
   208  		case snowmantest.GenesisID:
   209  			return snowmantest.Genesis, nil
   210  		default:
   211  			return nil, errUnknownBlock
   212  		}
   213  	}
   214  
   215  	var getRequest *common.Request
   216  	sender.SendGetF = func(_ context.Context, nodeID ids.NodeID, requestID uint32, blkID ids.ID) {
   217  		require.Nil(getRequest)
   218  		getRequest = &common.Request{
   219  			NodeID:    nodeID,
   220  			RequestID: requestID,
   221  		}
   222  		require.Equal(peerID, nodeID)
   223  		require.Contains([]ids.ID{
   224  			parent.ID(),
   225  			snowmantest.GenesisID,
   226  		}, blkID)
   227  	}
   228  
   229  	// Handling a pull query for [parent] should result in immediately
   230  	// responding with chits for [Genesis] along with a request for [parent].
   231  	require.NoError(engine.PullQuery(context.Background(), peerID, 15, parent.ID(), 1))
   232  	require.True(sendChitsCalled)
   233  	require.True(getBlockCalled)
   234  	require.NotNil(getRequest)
   235  
   236  	var queryRequest *common.Request
   237  	sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, blockID ids.ID, requestedHeight uint64) {
   238  		require.Nil(queryRequest)
   239  		require.Equal(set.Of(peerID), nodeIDs)
   240  		queryRequest = &common.Request{
   241  			NodeID:    peerID,
   242  			RequestID: requestID,
   243  		}
   244  		require.Equal(parent.ID(), blockID)
   245  		require.Equal(uint64(1), requestedHeight)
   246  	}
   247  
   248  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   249  		require.Equal(parent.Bytes(), b)
   250  		return parent, nil
   251  	}
   252  
   253  	// After receiving [parent], the engine will parse it, issue it, and then
   254  	// send a pull query.
   255  	require.NoError(engine.Put(context.Background(), getRequest.NodeID, getRequest.RequestID, parent.Bytes()))
   256  	require.NotNil(queryRequest)
   257  
   258  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   259  		switch blkID {
   260  		case parent.ID(), child.ID():
   261  			return nil, errUnknownBlock
   262  		}
   263  		require.FailNow(errUnknownBlock.Error())
   264  		return nil, errUnknownBlock
   265  	}
   266  	vm.ParseBlockF = nil
   267  
   268  	getRequest = nil
   269  	sender.SendGetF = func(_ context.Context, nodeID ids.NodeID, requestID uint32, blkID ids.ID) {
   270  		require.Nil(getRequest)
   271  		getRequest = &common.Request{
   272  			NodeID:    nodeID,
   273  			RequestID: requestID,
   274  		}
   275  		require.Equal(peerID, nodeID)
   276  		require.Equal(child.ID(), blkID)
   277  	}
   278  
   279  	// Handling chits for [child] register a voter job blocking on [child]'s
   280  	// issuance and send a request for [child].
   281  	require.NoError(engine.Chits(context.Background(), queryRequest.NodeID, queryRequest.RequestID, child.ID(), child.ID(), child.ID()))
   282  
   283  	queryRequest = nil
   284  	sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, blockID ids.ID, requestedHeight uint64) {
   285  		require.Nil(queryRequest)
   286  		require.Equal(set.Of(peerID), nodeIDs)
   287  		queryRequest = &common.Request{
   288  			NodeID:    peerID,
   289  			RequestID: requestID,
   290  		}
   291  		require.Equal(child.ID(), blockID)
   292  		require.Equal(uint64(1), requestedHeight)
   293  	}
   294  
   295  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   296  		require.Equal(child.Bytes(), b)
   297  
   298  		vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   299  			switch blkID {
   300  			case parent.ID():
   301  				return parent, nil
   302  			case child.ID():
   303  				return child, nil
   304  			}
   305  			require.FailNow(errUnknownBlock.Error())
   306  			return nil, errUnknownBlock
   307  		}
   308  
   309  		return child, nil
   310  	}
   311  
   312  	// After receiving [child], the engine will parse it, issue it, and then
   313  	// apply the votes received during the poll for [parent]. Applying the votes
   314  	// should cause both [parent] and [child] to be accepted.
   315  	require.NoError(engine.Put(context.Background(), getRequest.NodeID, getRequest.RequestID, child.Bytes()))
   316  	require.Equal(choices.Accepted, parent.Status())
   317  	require.Equal(choices.Accepted, child.Status())
   318  	require.Zero(engine.blocked.NumDependencies())
   319  }
   320  
   321  func TestEngineMultipleQuery(t *testing.T) {
   322  	require := require.New(t)
   323  
   324  	engCfg := DefaultConfig(t)
   325  	engCfg.Params = snowball.Parameters{
   326  		K:                     3,
   327  		AlphaPreference:       2,
   328  		AlphaConfidence:       2,
   329  		Beta:                  1,
   330  		ConcurrentRepolls:     1,
   331  		OptimalProcessing:     1,
   332  		MaxOutstandingItems:   1,
   333  		MaxItemProcessingTime: 1,
   334  	}
   335  
   336  	vals := validators.NewManager()
   337  	engCfg.Validators = vals
   338  
   339  	vdr0 := ids.GenerateTestNodeID()
   340  	vdr1 := ids.GenerateTestNodeID()
   341  	vdr2 := ids.GenerateTestNodeID()
   342  
   343  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr0, nil, ids.Empty, 1))
   344  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr1, nil, ids.Empty, 1))
   345  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr2, nil, ids.Empty, 1))
   346  
   347  	sender := &common.SenderTest{T: t}
   348  	engCfg.Sender = sender
   349  	sender.Default(true)
   350  
   351  	vm := &block.TestVM{}
   352  	vm.T = t
   353  	engCfg.VM = vm
   354  
   355  	vm.Default(true)
   356  	vm.CantSetState = false
   357  	vm.CantSetPreference = false
   358  
   359  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
   360  		return snowmantest.GenesisID, nil
   361  	}
   362  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   363  		require.Equal(snowmantest.GenesisID, blkID)
   364  		return snowmantest.Genesis, nil
   365  	}
   366  
   367  	te, err := New(engCfg)
   368  	require.NoError(err)
   369  
   370  	require.NoError(te.Start(context.Background(), 0))
   371  
   372  	vm.GetBlockF = nil
   373  	vm.LastAcceptedF = nil
   374  
   375  	blk0 := snowmantest.BuildChild(snowmantest.Genesis)
   376  	blk1 := snowmantest.BuildChild(blk0)
   377  
   378  	queried := new(bool)
   379  	queryRequestID := new(uint32)
   380  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
   381  		require.False(*queried)
   382  		*queried = true
   383  		*queryRequestID = requestID
   384  		vdrSet := set.Of(vdr0, vdr1, vdr2)
   385  		require.Equal(vdrSet, inVdrs)
   386  		require.Equal(blk0.ID(), blkID)
   387  		require.Equal(uint64(1), requestedHeight)
   388  	}
   389  
   390  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   391  		switch blkID {
   392  		case snowmantest.GenesisID:
   393  			return snowmantest.Genesis, nil
   394  		default:
   395  			return nil, errUnknownBlock
   396  		}
   397  	}
   398  
   399  	require.NoError(te.issue(
   400  		context.Background(),
   401  		te.Ctx.NodeID,
   402  		blk0,
   403  		false,
   404  		te.metrics.issued.WithLabelValues(unknownSource),
   405  	))
   406  
   407  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
   408  		switch id {
   409  		case snowmantest.GenesisID:
   410  			return snowmantest.Genesis, nil
   411  		case blk0.ID():
   412  			return blk0, nil
   413  		case blk1.ID():
   414  			return nil, errUnknownBlock
   415  		}
   416  		require.FailNow(errUnknownBlock.Error())
   417  		return nil, errUnknownBlock
   418  	}
   419  
   420  	asked := new(bool)
   421  	getRequestID := new(uint32)
   422  	sender.SendGetF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, blkID ids.ID) {
   423  		require.False(*asked)
   424  		*asked = true
   425  		*getRequestID = requestID
   426  		require.Equal(vdr0, inVdr)
   427  		require.Equal(blk1.ID(), blkID)
   428  	}
   429  	require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk1.ID(), blk1.ID(), blk1.ID()))
   430  	require.NoError(te.Chits(context.Background(), vdr1, *queryRequestID, blk1.ID(), blk1.ID(), blk1.ID()))
   431  
   432  	vm.ParseBlockF = func(context.Context, []byte) (snowman.Block, error) {
   433  		vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   434  			switch {
   435  			case blkID == blk0.ID():
   436  				return blk0, nil
   437  			case blkID == blk1.ID():
   438  				return blk1, nil
   439  			}
   440  			require.FailNow(errUnknownBlock.Error())
   441  			return nil, errUnknownBlock
   442  		}
   443  
   444  		return blk1, nil
   445  	}
   446  
   447  	*queried = false
   448  	secondQueryRequestID := new(uint32)
   449  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
   450  		require.False(*queried)
   451  		*queried = true
   452  		*secondQueryRequestID = requestID
   453  		vdrSet := set.Of(vdr0, vdr1, vdr2)
   454  		require.Equal(vdrSet, inVdrs)
   455  		require.Equal(blk1.ID(), blkID)
   456  		require.Equal(uint64(1), requestedHeight)
   457  	}
   458  	require.NoError(te.Put(context.Background(), vdr0, *getRequestID, blk1.Bytes()))
   459  
   460  	// Should be dropped because the query was already filled
   461  	require.NoError(te.Chits(context.Background(), vdr2, *queryRequestID, blk0.ID(), blk0.ID(), blk0.ID()))
   462  
   463  	require.Equal(choices.Accepted, blk1.Status())
   464  	require.Zero(te.blocked.NumDependencies())
   465  }
   466  
   467  func TestEngineBlockedIssue(t *testing.T) {
   468  	require := require.New(t)
   469  
   470  	_, _, sender, vm, te := setup(t, DefaultConfig(t))
   471  
   472  	sender.Default(false)
   473  
   474  	blk0 := snowmantest.BuildChild(snowmantest.Genesis)
   475  	blk1 := snowmantest.BuildChild(blk0)
   476  
   477  	sender.SendGetF = func(context.Context, ids.NodeID, uint32, ids.ID) {}
   478  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   479  		switch blkID {
   480  		case snowmantest.GenesisID:
   481  			return snowmantest.Genesis, nil
   482  		case blk0.ID():
   483  			return blk0, nil
   484  		default:
   485  			return nil, errUnknownBlock
   486  		}
   487  	}
   488  
   489  	require.NoError(te.issue(
   490  		context.Background(),
   491  		te.Ctx.NodeID,
   492  		blk1,
   493  		false,
   494  		te.metrics.issued.WithLabelValues(unknownSource),
   495  	))
   496  
   497  	require.NoError(te.issue(
   498  		context.Background(),
   499  		te.Ctx.NodeID,
   500  		blk0,
   501  		false,
   502  		te.metrics.issued.WithLabelValues(unknownSource),
   503  	))
   504  
   505  	require.Equal(blk1.ID(), te.Consensus.Preference())
   506  }
   507  
   508  func TestEngineRespondsToGetRequest(t *testing.T) {
   509  	require := require.New(t)
   510  
   511  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   512  
   513  	sender.Default(false)
   514  
   515  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
   516  		require.Equal(snowmantest.GenesisID, id)
   517  		return snowmantest.Genesis, nil
   518  	}
   519  
   520  	var sentPut bool
   521  	sender.SendPutF = func(_ context.Context, nodeID ids.NodeID, requestID uint32, blk []byte) {
   522  		require.False(sentPut)
   523  		sentPut = true
   524  
   525  		require.Equal(vdr, nodeID)
   526  		require.Equal(uint32(123), requestID)
   527  		require.Equal(snowmantest.GenesisBytes, blk)
   528  	}
   529  
   530  	require.NoError(te.Get(context.Background(), vdr, 123, snowmantest.GenesisID))
   531  	require.True(sentPut)
   532  }
   533  
   534  func TestEnginePushQuery(t *testing.T) {
   535  	require := require.New(t)
   536  
   537  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   538  
   539  	sender.Default(true)
   540  
   541  	blk := snowmantest.BuildChild(snowmantest.Genesis)
   542  
   543  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   544  		if bytes.Equal(b, blk.Bytes()) {
   545  			return blk, nil
   546  		}
   547  		return nil, errUnknownBytes
   548  	}
   549  
   550  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   551  		switch blkID {
   552  		case snowmantest.GenesisID:
   553  			return snowmantest.Genesis, nil
   554  		case blk.ID():
   555  			return blk, nil
   556  		default:
   557  			return nil, errUnknownBlock
   558  		}
   559  	}
   560  
   561  	chitted := new(bool)
   562  	sender.SendChitsF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDByHeight ids.ID, acceptedID ids.ID) {
   563  		require.False(*chitted)
   564  		*chitted = true
   565  		require.Equal(vdr, inVdr)
   566  		require.Equal(uint32(20), requestID)
   567  		require.Equal(snowmantest.GenesisID, preferredID)
   568  		require.Equal(snowmantest.GenesisID, preferredIDByHeight)
   569  		require.Equal(snowmantest.GenesisID, acceptedID)
   570  	}
   571  
   572  	queried := new(bool)
   573  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], _ uint32, blkID ids.ID, requestedHeight uint64) {
   574  		require.False(*queried)
   575  		*queried = true
   576  		vdrSet := set.Of(vdr)
   577  		require.True(inVdrs.Equals(vdrSet))
   578  		require.Equal(blk.ID(), blkID)
   579  		require.Equal(uint64(1), requestedHeight)
   580  	}
   581  
   582  	require.NoError(te.PushQuery(context.Background(), vdr, 20, blk.Bytes(), 1))
   583  
   584  	require.True(*chitted)
   585  	require.True(*queried)
   586  }
   587  
   588  func TestEngineBuildBlock(t *testing.T) {
   589  	require := require.New(t)
   590  
   591  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   592  
   593  	sender.Default(true)
   594  
   595  	blk := snowmantest.BuildChild(snowmantest.Genesis)
   596  
   597  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   598  		switch blkID {
   599  		case snowmantest.GenesisID:
   600  			return snowmantest.Genesis, nil
   601  		default:
   602  			return nil, errUnknownBlock
   603  		}
   604  	}
   605  
   606  	sender.SendPullQueryF = func(context.Context, set.Set[ids.NodeID], uint32, ids.ID, uint64) {
   607  		require.FailNow("should not be sending pulls when we are the block producer")
   608  	}
   609  
   610  	pushSent := new(bool)
   611  	sender.SendPushQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], _ uint32, _ []byte, _ uint64) {
   612  		require.False(*pushSent)
   613  		*pushSent = true
   614  		vdrSet := set.Of(vdr)
   615  		require.Equal(vdrSet, inVdrs)
   616  	}
   617  
   618  	vm.BuildBlockF = func(context.Context) (snowman.Block, error) {
   619  		return blk, nil
   620  	}
   621  	require.NoError(te.Notify(context.Background(), common.PendingTxs))
   622  
   623  	require.True(*pushSent)
   624  }
   625  
   626  func TestEngineRepoll(t *testing.T) {
   627  	require := require.New(t)
   628  	vdr, _, sender, _, te := setup(t, DefaultConfig(t))
   629  
   630  	sender.Default(true)
   631  
   632  	queried := new(bool)
   633  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], _ uint32, _ ids.ID, _ uint64) {
   634  		require.False(*queried)
   635  		*queried = true
   636  		vdrSet := set.Of(vdr)
   637  		require.Equal(vdrSet, inVdrs)
   638  	}
   639  
   640  	te.repoll(context.Background())
   641  
   642  	require.True(*queried)
   643  }
   644  
   645  func TestVoteCanceling(t *testing.T) {
   646  	require := require.New(t)
   647  
   648  	engCfg := DefaultConfig(t)
   649  	engCfg.Params = snowball.Parameters{
   650  		K:                     3,
   651  		AlphaPreference:       2,
   652  		AlphaConfidence:       2,
   653  		Beta:                  1,
   654  		ConcurrentRepolls:     1,
   655  		OptimalProcessing:     1,
   656  		MaxOutstandingItems:   1,
   657  		MaxItemProcessingTime: 1,
   658  	}
   659  
   660  	vals := validators.NewManager()
   661  	engCfg.Validators = vals
   662  
   663  	vdr0 := ids.GenerateTestNodeID()
   664  	vdr1 := ids.GenerateTestNodeID()
   665  	vdr2 := ids.GenerateTestNodeID()
   666  
   667  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr0, nil, ids.Empty, 1))
   668  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr1, nil, ids.Empty, 1))
   669  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr2, nil, ids.Empty, 1))
   670  
   671  	sender := &common.SenderTest{T: t}
   672  	engCfg.Sender = sender
   673  	sender.Default(true)
   674  
   675  	vm := &block.TestVM{}
   676  	vm.T = t
   677  	engCfg.VM = vm
   678  
   679  	vm.Default(true)
   680  	vm.CantSetState = false
   681  	vm.CantSetPreference = false
   682  
   683  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
   684  		return snowmantest.GenesisID, nil
   685  	}
   686  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
   687  		require.Equal(snowmantest.GenesisID, id)
   688  		return snowmantest.Genesis, nil
   689  	}
   690  
   691  	te, err := New(engCfg)
   692  	require.NoError(err)
   693  
   694  	require.NoError(te.Start(context.Background(), 0))
   695  
   696  	vm.LastAcceptedF = nil
   697  
   698  	blk := snowmantest.BuildChild(snowmantest.Genesis)
   699  
   700  	queried := new(bool)
   701  	queryRequestID := new(uint32)
   702  	sender.SendPushQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkBytes []byte, requestedHeight uint64) {
   703  		require.False(*queried)
   704  		*queried = true
   705  		*queryRequestID = requestID
   706  		vdrSet := set.Of(vdr0, vdr1, vdr2)
   707  		require.Equal(vdrSet, inVdrs)
   708  		require.Equal(blk.Bytes(), blkBytes)
   709  		require.Equal(uint64(1), requestedHeight)
   710  	}
   711  
   712  	require.NoError(te.issue(
   713  		context.Background(),
   714  		te.Ctx.NodeID,
   715  		blk,
   716  		true,
   717  		te.metrics.issued.WithLabelValues(unknownSource),
   718  	))
   719  
   720  	require.Equal(1, te.polls.Len())
   721  
   722  	require.NoError(te.QueryFailed(context.Background(), vdr0, *queryRequestID))
   723  
   724  	require.Equal(1, te.polls.Len())
   725  
   726  	repolled := new(bool)
   727  	sender.SendPullQueryF = func(context.Context, set.Set[ids.NodeID], uint32, ids.ID, uint64) {
   728  		*repolled = true
   729  	}
   730  	require.NoError(te.QueryFailed(context.Background(), vdr1, *queryRequestID))
   731  
   732  	require.True(*repolled)
   733  }
   734  
   735  func TestEngineNoQuery(t *testing.T) {
   736  	require := require.New(t)
   737  
   738  	engCfg := DefaultConfig(t)
   739  
   740  	sender := &common.SenderTest{T: t}
   741  	engCfg.Sender = sender
   742  	sender.Default(true)
   743  
   744  	vm := &block.TestVM{}
   745  	vm.T = t
   746  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
   747  		return snowmantest.GenesisID, nil
   748  	}
   749  
   750  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   751  		if blkID == snowmantest.GenesisID {
   752  			return snowmantest.Genesis, nil
   753  		}
   754  		return nil, errUnknownBlock
   755  	}
   756  
   757  	engCfg.VM = vm
   758  
   759  	te, err := New(engCfg)
   760  	require.NoError(err)
   761  
   762  	require.NoError(te.Start(context.Background(), 0))
   763  
   764  	blk := snowmantest.BuildChild(snowmantest.Genesis)
   765  
   766  	require.NoError(te.issue(
   767  		context.Background(),
   768  		te.Ctx.NodeID,
   769  		blk,
   770  		false,
   771  		te.metrics.issued.WithLabelValues(unknownSource),
   772  	))
   773  }
   774  
   775  func TestEngineNoRepollQuery(t *testing.T) {
   776  	require := require.New(t)
   777  
   778  	engCfg := DefaultConfig(t)
   779  
   780  	sender := &common.SenderTest{T: t}
   781  	engCfg.Sender = sender
   782  	sender.Default(true)
   783  
   784  	vm := &block.TestVM{}
   785  	vm.T = t
   786  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
   787  		return snowmantest.GenesisID, nil
   788  	}
   789  
   790  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   791  		if blkID == snowmantest.GenesisID {
   792  			return snowmantest.Genesis, nil
   793  		}
   794  		return nil, errUnknownBlock
   795  	}
   796  
   797  	engCfg.VM = vm
   798  
   799  	te, err := New(engCfg)
   800  	require.NoError(err)
   801  
   802  	require.NoError(te.Start(context.Background(), 0))
   803  
   804  	te.repoll(context.Background())
   805  }
   806  
   807  func TestEngineAbandonQuery(t *testing.T) {
   808  	require := require.New(t)
   809  
   810  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   811  
   812  	sender.Default(true)
   813  
   814  	blkID := ids.GenerateTestID()
   815  
   816  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
   817  		require.Equal(blkID, id)
   818  		return nil, errUnknownBlock
   819  	}
   820  
   821  	reqID := new(uint32)
   822  	sender.SendGetF = func(_ context.Context, _ ids.NodeID, requestID uint32, _ ids.ID) {
   823  		*reqID = requestID
   824  	}
   825  
   826  	sender.CantSendChits = false
   827  
   828  	require.NoError(te.PullQuery(context.Background(), vdr, 0, blkID, 0))
   829  
   830  	require.Equal(1, te.blkReqs.Len())
   831  
   832  	require.NoError(te.GetFailed(context.Background(), vdr, *reqID))
   833  
   834  	require.Zero(te.blkReqs.Len())
   835  }
   836  
   837  func TestEngineAbandonChit(t *testing.T) {
   838  	require := require.New(t)
   839  
   840  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   841  
   842  	sender.Default(true)
   843  
   844  	blk := snowmantest.BuildChild(snowmantest.Genesis)
   845  
   846  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   847  		switch blkID {
   848  		case snowmantest.GenesisID:
   849  			return snowmantest.Genesis, nil
   850  		case blk.ID():
   851  			return nil, errUnknownBlock
   852  		}
   853  		require.FailNow(errUnknownBlock.Error())
   854  		return nil, errUnknownBlock
   855  	}
   856  
   857  	var reqID uint32
   858  	sender.SendPullQueryF = func(_ context.Context, _ set.Set[ids.NodeID], requestID uint32, _ ids.ID, _ uint64) {
   859  		reqID = requestID
   860  	}
   861  
   862  	require.NoError(te.issue(
   863  		context.Background(),
   864  		te.Ctx.NodeID,
   865  		blk,
   866  		false,
   867  		te.metrics.issued.WithLabelValues(unknownSource),
   868  	))
   869  
   870  	fakeBlkID := ids.GenerateTestID()
   871  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
   872  		require.Equal(fakeBlkID, id)
   873  		return nil, errUnknownBlock
   874  	}
   875  
   876  	sender.SendGetF = func(_ context.Context, _ ids.NodeID, requestID uint32, _ ids.ID) {
   877  		reqID = requestID
   878  	}
   879  
   880  	// Register a voter dependency on an unknown block.
   881  	require.NoError(te.Chits(context.Background(), vdr, reqID, fakeBlkID, fakeBlkID, fakeBlkID))
   882  	require.Equal(1, te.blocked.NumDependencies())
   883  
   884  	sender.CantSendPullQuery = false
   885  
   886  	require.NoError(te.GetFailed(context.Background(), vdr, reqID))
   887  	require.Zero(te.blocked.NumDependencies())
   888  }
   889  
   890  func TestEngineAbandonChitWithUnexpectedPutBlock(t *testing.T) {
   891  	require := require.New(t)
   892  
   893  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   894  
   895  	sender.Default(true)
   896  
   897  	blk := snowmantest.BuildChild(snowmantest.Genesis)
   898  
   899  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   900  		switch blkID {
   901  		case snowmantest.GenesisID:
   902  			return snowmantest.Genesis, nil
   903  		case blk.ID():
   904  			return nil, errUnknownBlock
   905  		}
   906  		require.FailNow(errUnknownBlock.Error())
   907  		return nil, errUnknownBlock
   908  	}
   909  
   910  	var reqID uint32
   911  	sender.SendPushQueryF = func(_ context.Context, _ set.Set[ids.NodeID], requestID uint32, _ []byte, _ uint64) {
   912  		reqID = requestID
   913  	}
   914  
   915  	require.NoError(te.issue(
   916  		context.Background(),
   917  		te.Ctx.NodeID,
   918  		blk,
   919  		true,
   920  		te.metrics.issued.WithLabelValues(unknownSource),
   921  	))
   922  
   923  	fakeBlkID := ids.GenerateTestID()
   924  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
   925  		require.Equal(fakeBlkID, id)
   926  		return nil, errUnknownBlock
   927  	}
   928  
   929  	sender.SendGetF = func(_ context.Context, _ ids.NodeID, requestID uint32, _ ids.ID) {
   930  		reqID = requestID
   931  	}
   932  
   933  	// Register a voter dependency on an unknown block.
   934  	require.NoError(te.Chits(context.Background(), vdr, reqID, fakeBlkID, fakeBlkID, fakeBlkID))
   935  	require.Equal(1, te.blocked.NumDependencies())
   936  
   937  	sender.CantSendPullQuery = false
   938  
   939  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   940  		require.Equal(snowmantest.GenesisBytes, b)
   941  		return snowmantest.Genesis, nil
   942  	}
   943  
   944  	// Respond with an unexpected block and verify that the request is correctly
   945  	// cleared.
   946  	require.NoError(te.Put(context.Background(), vdr, reqID, snowmantest.GenesisBytes))
   947  	require.Zero(te.blocked.NumDependencies())
   948  }
   949  
   950  func TestEngineBlockingChitRequest(t *testing.T) {
   951  	require := require.New(t)
   952  
   953  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
   954  
   955  	sender.Default(true)
   956  
   957  	missingBlk := snowmantest.BuildChild(snowmantest.Genesis)
   958  	parentBlk := snowmantest.BuildChild(missingBlk)
   959  	blockingBlk := snowmantest.BuildChild(parentBlk)
   960  
   961  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   962  		switch blkID {
   963  		case snowmantest.GenesisID:
   964  			return snowmantest.Genesis, nil
   965  		case blockingBlk.ID():
   966  			return blockingBlk, nil
   967  		default:
   968  			return nil, errUnknownBlock
   969  		}
   970  	}
   971  
   972  	sender.SendGetF = func(context.Context, ids.NodeID, uint32, ids.ID) {}
   973  
   974  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   975  		require.Equal(blockingBlk.Bytes(), b)
   976  		return blockingBlk, nil
   977  	}
   978  
   979  	require.NoError(te.issue(
   980  		context.Background(),
   981  		te.Ctx.NodeID,
   982  		parentBlk,
   983  		false,
   984  		te.metrics.issued.WithLabelValues(unknownSource),
   985  	))
   986  
   987  	sender.CantSendChits = false
   988  
   989  	require.NoError(te.PushQuery(context.Background(), vdr, 0, blockingBlk.Bytes(), 0))
   990  
   991  	require.Equal(2, te.blocked.NumDependencies())
   992  
   993  	sender.CantSendPullQuery = false
   994  
   995  	require.NoError(te.issue(
   996  		context.Background(),
   997  		te.Ctx.NodeID,
   998  		missingBlk,
   999  		false,
  1000  		te.metrics.issued.WithLabelValues(unknownSource),
  1001  	))
  1002  
  1003  	require.Zero(te.blocked.NumDependencies())
  1004  }
  1005  
  1006  func TestEngineBlockingChitResponse(t *testing.T) {
  1007  	require := require.New(t)
  1008  
  1009  	config := DefaultConfig(t)
  1010  
  1011  	peerID, _, sender, vm, te := setup(t, config)
  1012  
  1013  	sender.Default(true)
  1014  
  1015  	issuedBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1016  
  1017  	missingBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1018  	blockingBlk := snowmantest.BuildChild(missingBlk)
  1019  
  1020  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1021  		switch blkID {
  1022  		case snowmantest.GenesisID:
  1023  			return snowmantest.Genesis, nil
  1024  		case issuedBlk.ID():
  1025  			return issuedBlk, nil
  1026  		case blockingBlk.ID():
  1027  			return blockingBlk, nil
  1028  		default:
  1029  			return nil, errUnknownBlock
  1030  		}
  1031  	}
  1032  	vm.ParseBlockF = func(_ context.Context, blkBytes []byte) (snowman.Block, error) {
  1033  		switch {
  1034  		case bytes.Equal(snowmantest.GenesisBytes, blkBytes):
  1035  			return snowmantest.Genesis, nil
  1036  		case bytes.Equal(issuedBlk.Bytes(), blkBytes):
  1037  			return issuedBlk, nil
  1038  		case bytes.Equal(missingBlk.Bytes(), blkBytes):
  1039  			return missingBlk, nil
  1040  		case bytes.Equal(blockingBlk.Bytes(), blkBytes):
  1041  			return blockingBlk, nil
  1042  		default:
  1043  			return nil, errUnknownBlock
  1044  		}
  1045  	}
  1046  
  1047  	var getRequest *common.Request
  1048  	sender.SendGetF = func(_ context.Context, nodeID ids.NodeID, requestID uint32, blkID ids.ID) {
  1049  		require.Nil(getRequest)
  1050  		getRequest = &common.Request{
  1051  			NodeID:    nodeID,
  1052  			RequestID: requestID,
  1053  		}
  1054  		require.Equal(missingBlk.ID(), blkID)
  1055  	}
  1056  
  1057  	// Issuing [blockingBlk] will register an issuer job for [blockingBlk]
  1058  	// awaiting on [missingBlk]. It will also send a request for [missingBlk].
  1059  	require.NoError(te.Put(
  1060  		context.Background(),
  1061  		peerID,
  1062  		0,
  1063  		blockingBlk.Bytes(),
  1064  	))
  1065  
  1066  	var queryRequest *common.Request
  1067  	sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  1068  		require.Nil(queryRequest)
  1069  		require.Equal(set.Of(peerID), nodeIDs)
  1070  		queryRequest = &common.Request{
  1071  			NodeID:    peerID,
  1072  			RequestID: requestID,
  1073  		}
  1074  		require.Equal(issuedBlk.ID(), blkID)
  1075  		require.Equal(uint64(1), requestedHeight)
  1076  	}
  1077  
  1078  	// Issuing [issuedBlk] will immediately adds [issuedBlk] to consensus, sets
  1079  	// it as the preferred block, and sends a query for [issuedBlk].
  1080  	require.NoError(te.Put(
  1081  		context.Background(),
  1082  		peerID,
  1083  		0,
  1084  		issuedBlk.Bytes(),
  1085  	))
  1086  
  1087  	sender.SendPullQueryF = nil
  1088  
  1089  	// In response to the query for [issuedBlk], the peer is responding with,
  1090  	// the currently pending issuance, [blockingBlk]. The direct conflict of
  1091  	// [issuedBlk] is [missingBlk]. This registers a voter job dependent on
  1092  	// [blockingBlk] and [missingBlk].
  1093  	require.NoError(te.Chits(
  1094  		context.Background(),
  1095  		queryRequest.NodeID,
  1096  		queryRequest.RequestID,
  1097  		blockingBlk.ID(),
  1098  		missingBlk.ID(),
  1099  		blockingBlk.ID(),
  1100  	))
  1101  	require.Equal(2, te.blocked.NumDependencies())
  1102  
  1103  	queryRequest = nil
  1104  	sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  1105  		require.Nil(queryRequest)
  1106  		require.Equal(set.Of(peerID), nodeIDs)
  1107  		queryRequest = &common.Request{
  1108  			NodeID:    peerID,
  1109  			RequestID: requestID,
  1110  		}
  1111  		require.Equal(blockingBlk.ID(), blkID)
  1112  		require.Equal(uint64(1), requestedHeight)
  1113  	}
  1114  
  1115  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1116  		switch blkID {
  1117  		case snowmantest.GenesisID:
  1118  			return snowmantest.Genesis, nil
  1119  		case issuedBlk.ID():
  1120  			return issuedBlk, nil
  1121  		case missingBlk.ID():
  1122  			return missingBlk, nil
  1123  		case blockingBlk.ID():
  1124  			return blockingBlk, nil
  1125  		default:
  1126  			return nil, errUnknownBlock
  1127  		}
  1128  	}
  1129  
  1130  	// Issuing [missingBlk] will add the block into consensus. However, it will
  1131  	// not send a query for it as it is not the preferred block.
  1132  	require.NoError(te.Put(
  1133  		context.Background(),
  1134  		getRequest.NodeID,
  1135  		getRequest.RequestID,
  1136  		missingBlk.Bytes(),
  1137  	))
  1138  	require.Equal(choices.Accepted, missingBlk.Status())
  1139  	require.Equal(choices.Accepted, blockingBlk.Status())
  1140  	require.Equal(choices.Rejected, issuedBlk.Status())
  1141  }
  1142  
  1143  func TestEngineRetryFetch(t *testing.T) {
  1144  	require := require.New(t)
  1145  
  1146  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  1147  
  1148  	sender.Default(true)
  1149  
  1150  	missingBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1151  
  1152  	vm.CantGetBlock = false
  1153  
  1154  	reqID := new(uint32)
  1155  	sender.SendGetF = func(_ context.Context, _ ids.NodeID, requestID uint32, _ ids.ID) {
  1156  		*reqID = requestID
  1157  	}
  1158  	sender.CantSendChits = false
  1159  
  1160  	require.NoError(te.PullQuery(context.Background(), vdr, 0, missingBlk.ID(), 0))
  1161  
  1162  	vm.CantGetBlock = true
  1163  	sender.SendGetF = nil
  1164  
  1165  	require.NoError(te.GetFailed(context.Background(), vdr, *reqID))
  1166  
  1167  	vm.CantGetBlock = false
  1168  
  1169  	called := new(bool)
  1170  	sender.SendGetF = func(context.Context, ids.NodeID, uint32, ids.ID) {
  1171  		*called = true
  1172  	}
  1173  
  1174  	require.NoError(te.PullQuery(context.Background(), vdr, 0, missingBlk.ID(), 0))
  1175  
  1176  	vm.CantGetBlock = true
  1177  	sender.SendGetF = nil
  1178  
  1179  	require.True(*called)
  1180  }
  1181  
  1182  func TestEngineUndeclaredDependencyDeadlock(t *testing.T) {
  1183  	require := require.New(t)
  1184  
  1185  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  1186  
  1187  	sender.Default(true)
  1188  
  1189  	validBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1190  	invalidBlk := snowmantest.BuildChild(validBlk)
  1191  	invalidBlk.VerifyV = errTest
  1192  
  1193  	invalidBlkID := invalidBlk.ID()
  1194  
  1195  	reqID := new(uint32)
  1196  	sender.SendPullQueryF = func(_ context.Context, _ set.Set[ids.NodeID], requestID uint32, _ ids.ID, _ uint64) {
  1197  		*reqID = requestID
  1198  	}
  1199  
  1200  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1201  		switch blkID {
  1202  		case snowmantest.GenesisID:
  1203  			return snowmantest.Genesis, nil
  1204  		case validBlk.ID():
  1205  			return validBlk, nil
  1206  		case invalidBlk.ID():
  1207  			return invalidBlk, nil
  1208  		default:
  1209  			return nil, errUnknownBlock
  1210  		}
  1211  	}
  1212  	require.NoError(te.issue(
  1213  		context.Background(),
  1214  		te.Ctx.NodeID,
  1215  		validBlk,
  1216  		false,
  1217  		te.metrics.issued.WithLabelValues(unknownSource),
  1218  	))
  1219  	sender.SendPushQueryF = nil
  1220  	require.NoError(te.issue(
  1221  		context.Background(),
  1222  		te.Ctx.NodeID,
  1223  		invalidBlk,
  1224  		false,
  1225  		te.metrics.issued.WithLabelValues(unknownSource),
  1226  	))
  1227  	require.NoError(te.Chits(context.Background(), vdr, *reqID, invalidBlkID, invalidBlkID, invalidBlkID))
  1228  
  1229  	require.Equal(choices.Accepted, validBlk.Status())
  1230  }
  1231  
  1232  func TestEngineGossip(t *testing.T) {
  1233  	require := require.New(t)
  1234  
  1235  	nodeID, _, sender, vm, te := setup(t, DefaultConfig(t))
  1236  
  1237  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
  1238  		return snowmantest.GenesisID, nil
  1239  	}
  1240  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1241  		require.Equal(snowmantest.GenesisID, blkID)
  1242  		return snowmantest.Genesis, nil
  1243  	}
  1244  
  1245  	var calledSendPullQuery bool
  1246  	sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], _ uint32, _ ids.ID, _ uint64) {
  1247  		calledSendPullQuery = true
  1248  		require.Equal(set.Of(nodeID), nodeIDs)
  1249  	}
  1250  
  1251  	require.NoError(te.Gossip(context.Background()))
  1252  
  1253  	require.True(calledSendPullQuery)
  1254  }
  1255  
  1256  func TestEngineInvalidBlockIgnoredFromUnexpectedPeer(t *testing.T) {
  1257  	require := require.New(t)
  1258  
  1259  	vdr, vdrs, sender, vm, te := setup(t, DefaultConfig(t))
  1260  
  1261  	secondVdr := ids.GenerateTestNodeID()
  1262  	require.NoError(vdrs.AddStaker(te.Ctx.SubnetID, secondVdr, nil, ids.Empty, 1))
  1263  
  1264  	sender.Default(true)
  1265  
  1266  	missingBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1267  	pendingBlk := snowmantest.BuildChild(missingBlk)
  1268  
  1269  	parsed := new(bool)
  1270  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1271  		if bytes.Equal(b, pendingBlk.Bytes()) {
  1272  			*parsed = true
  1273  			return pendingBlk, nil
  1274  		}
  1275  		return nil, errUnknownBlock
  1276  	}
  1277  
  1278  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1279  		switch blkID {
  1280  		case snowmantest.GenesisID:
  1281  			return snowmantest.Genesis, nil
  1282  		case pendingBlk.ID():
  1283  			if !*parsed {
  1284  				return nil, errUnknownBlock
  1285  			}
  1286  			return pendingBlk, nil
  1287  		default:
  1288  			return nil, errUnknownBlock
  1289  		}
  1290  	}
  1291  
  1292  	reqID := new(uint32)
  1293  	sender.SendGetF = func(_ context.Context, reqVdr ids.NodeID, requestID uint32, blkID ids.ID) {
  1294  		*reqID = requestID
  1295  		require.Equal(vdr, reqVdr)
  1296  		require.Equal(missingBlk.ID(), blkID)
  1297  	}
  1298  	sender.CantSendChits = false
  1299  
  1300  	require.NoError(te.PushQuery(context.Background(), vdr, 0, pendingBlk.Bytes(), 0))
  1301  
  1302  	require.NoError(te.Put(context.Background(), secondVdr, *reqID, []byte{3}))
  1303  
  1304  	*parsed = false
  1305  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1306  		if bytes.Equal(b, missingBlk.Bytes()) {
  1307  			*parsed = true
  1308  			return missingBlk, nil
  1309  		}
  1310  		return nil, errUnknownBlock
  1311  	}
  1312  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1313  		switch blkID {
  1314  		case snowmantest.GenesisID:
  1315  			return snowmantest.Genesis, nil
  1316  		case missingBlk.ID():
  1317  			if !*parsed {
  1318  				return nil, errUnknownBlock
  1319  			}
  1320  			return missingBlk, nil
  1321  		default:
  1322  			return nil, errUnknownBlock
  1323  		}
  1324  	}
  1325  	sender.CantSendPullQuery = false
  1326  
  1327  	require.NoError(te.Put(context.Background(), vdr, *reqID, missingBlk.Bytes()))
  1328  
  1329  	require.Equal(pendingBlk.ID(), te.Consensus.Preference())
  1330  }
  1331  
  1332  func TestEnginePushQueryRequestIDConflict(t *testing.T) {
  1333  	require := require.New(t)
  1334  
  1335  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  1336  
  1337  	sender.Default(true)
  1338  
  1339  	missingBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1340  	pendingBlk := snowmantest.BuildChild(missingBlk)
  1341  
  1342  	parsed := new(bool)
  1343  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1344  		if bytes.Equal(b, pendingBlk.Bytes()) {
  1345  			*parsed = true
  1346  			return pendingBlk, nil
  1347  		}
  1348  		return nil, errUnknownBlock
  1349  	}
  1350  
  1351  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1352  		switch blkID {
  1353  		case snowmantest.GenesisID:
  1354  			return snowmantest.Genesis, nil
  1355  		case pendingBlk.ID():
  1356  			if !*parsed {
  1357  				return nil, errUnknownBlock
  1358  			}
  1359  			return pendingBlk, nil
  1360  		default:
  1361  			return nil, errUnknownBlock
  1362  		}
  1363  	}
  1364  
  1365  	reqID := new(uint32)
  1366  	sender.SendGetF = func(_ context.Context, reqVdr ids.NodeID, requestID uint32, blkID ids.ID) {
  1367  		*reqID = requestID
  1368  		require.Equal(vdr, reqVdr)
  1369  		require.Equal(missingBlk.ID(), blkID)
  1370  	}
  1371  	sender.CantSendChits = false
  1372  
  1373  	require.NoError(te.PushQuery(context.Background(), vdr, 0, pendingBlk.Bytes(), 0))
  1374  
  1375  	sender.SendGetF = nil
  1376  	sender.CantSendGet = false
  1377  
  1378  	require.NoError(te.PushQuery(context.Background(), vdr, *reqID, []byte{3}, 0))
  1379  
  1380  	*parsed = false
  1381  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1382  		if bytes.Equal(b, missingBlk.Bytes()) {
  1383  			*parsed = true
  1384  			return missingBlk, nil
  1385  		}
  1386  		return nil, errUnknownBlock
  1387  	}
  1388  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1389  		switch blkID {
  1390  		case snowmantest.GenesisID:
  1391  			return snowmantest.Genesis, nil
  1392  		case missingBlk.ID():
  1393  			if !*parsed {
  1394  				return nil, errUnknownBlock
  1395  			}
  1396  			return missingBlk, nil
  1397  		default:
  1398  			return nil, errUnknownBlock
  1399  		}
  1400  	}
  1401  	sender.CantSendPullQuery = false
  1402  
  1403  	require.NoError(te.Put(context.Background(), vdr, *reqID, missingBlk.Bytes()))
  1404  
  1405  	require.Equal(pendingBlk.ID(), te.Consensus.Preference())
  1406  }
  1407  
  1408  func TestEngineAggressivePolling(t *testing.T) {
  1409  	require := require.New(t)
  1410  
  1411  	engCfg := DefaultConfig(t)
  1412  	engCfg.Params.ConcurrentRepolls = 2
  1413  	engCfg.Params.Beta = 2
  1414  
  1415  	vals := validators.NewManager()
  1416  	engCfg.Validators = vals
  1417  
  1418  	vdr := ids.GenerateTestNodeID()
  1419  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr, nil, ids.Empty, 1))
  1420  
  1421  	sender := &common.SenderTest{T: t}
  1422  	engCfg.Sender = sender
  1423  	sender.Default(true)
  1424  
  1425  	vm := &block.TestVM{}
  1426  	vm.T = t
  1427  	engCfg.VM = vm
  1428  
  1429  	vm.Default(true)
  1430  	vm.CantSetState = false
  1431  	vm.CantSetPreference = false
  1432  
  1433  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
  1434  		return snowmantest.GenesisID, nil
  1435  	}
  1436  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1437  		require.Equal(snowmantest.GenesisID, blkID)
  1438  		return snowmantest.Genesis, nil
  1439  	}
  1440  
  1441  	te, err := New(engCfg)
  1442  	require.NoError(err)
  1443  
  1444  	require.NoError(te.Start(context.Background(), 0))
  1445  
  1446  	vm.GetBlockF = nil
  1447  	vm.LastAcceptedF = nil
  1448  
  1449  	pendingBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1450  
  1451  	parsed := new(bool)
  1452  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1453  		if bytes.Equal(b, pendingBlk.Bytes()) {
  1454  			*parsed = true
  1455  			return pendingBlk, nil
  1456  		}
  1457  		return nil, errUnknownBlock
  1458  	}
  1459  
  1460  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1461  		switch blkID {
  1462  		case snowmantest.GenesisID:
  1463  			return snowmantest.Genesis, nil
  1464  		case pendingBlk.ID():
  1465  			if !*parsed {
  1466  				return nil, errUnknownBlock
  1467  			}
  1468  			return pendingBlk, nil
  1469  		default:
  1470  			return nil, errUnknownBlock
  1471  		}
  1472  	}
  1473  
  1474  	numPulled := new(int)
  1475  	sender.SendPullQueryF = func(context.Context, set.Set[ids.NodeID], uint32, ids.ID, uint64) {
  1476  		*numPulled++
  1477  	}
  1478  
  1479  	require.NoError(te.Put(context.Background(), vdr, 0, pendingBlk.Bytes()))
  1480  
  1481  	require.Equal(2, *numPulled)
  1482  }
  1483  
  1484  func TestEngineDoubleChit(t *testing.T) {
  1485  	require := require.New(t)
  1486  
  1487  	engCfg := DefaultConfig(t)
  1488  	engCfg.Params = snowball.Parameters{
  1489  		K:                     2,
  1490  		AlphaPreference:       2,
  1491  		AlphaConfidence:       2,
  1492  		Beta:                  1,
  1493  		ConcurrentRepolls:     1,
  1494  		OptimalProcessing:     1,
  1495  		MaxOutstandingItems:   1,
  1496  		MaxItemProcessingTime: 1,
  1497  	}
  1498  
  1499  	vals := validators.NewManager()
  1500  	engCfg.Validators = vals
  1501  
  1502  	vdr0 := ids.GenerateTestNodeID()
  1503  	vdr1 := ids.GenerateTestNodeID()
  1504  
  1505  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr0, nil, ids.Empty, 1))
  1506  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr1, nil, ids.Empty, 1))
  1507  
  1508  	sender := &common.SenderTest{T: t}
  1509  	engCfg.Sender = sender
  1510  
  1511  	sender.Default(true)
  1512  
  1513  	vm := &block.TestVM{}
  1514  	vm.T = t
  1515  	engCfg.VM = vm
  1516  
  1517  	vm.Default(true)
  1518  	vm.CantSetState = false
  1519  	vm.CantSetPreference = false
  1520  
  1521  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
  1522  		return snowmantest.GenesisID, nil
  1523  	}
  1524  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
  1525  		require.Equal(snowmantest.GenesisID, id)
  1526  		return snowmantest.Genesis, nil
  1527  	}
  1528  
  1529  	te, err := New(engCfg)
  1530  	require.NoError(err)
  1531  
  1532  	require.NoError(te.Start(context.Background(), 0))
  1533  
  1534  	vm.LastAcceptedF = nil
  1535  
  1536  	blk := snowmantest.BuildChild(snowmantest.Genesis)
  1537  
  1538  	queried := new(bool)
  1539  	queryRequestID := new(uint32)
  1540  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  1541  		require.False((*queried))
  1542  		*queried = true
  1543  		*queryRequestID = requestID
  1544  		vdrSet := set.Of(vdr0, vdr1)
  1545  		require.Equal(vdrSet, inVdrs)
  1546  		require.Equal(blk.ID(), blkID)
  1547  		require.Equal(uint64(1), requestedHeight)
  1548  	}
  1549  	require.NoError(te.issue(
  1550  		context.Background(),
  1551  		te.Ctx.NodeID,
  1552  		blk,
  1553  		false,
  1554  		te.metrics.issued.WithLabelValues(unknownSource),
  1555  	))
  1556  
  1557  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
  1558  		switch id {
  1559  		case snowmantest.GenesisID:
  1560  			return snowmantest.Genesis, nil
  1561  		case blk.ID():
  1562  			return blk, nil
  1563  		}
  1564  		require.FailNow(errUnknownBlock.Error())
  1565  		return nil, errUnknownBlock
  1566  	}
  1567  
  1568  	require.Equal(choices.Processing, blk.Status())
  1569  
  1570  	require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk.ID(), blk.ID(), blk.ID()))
  1571  	require.Equal(choices.Processing, blk.Status())
  1572  
  1573  	require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk.ID(), blk.ID(), blk.ID()))
  1574  	require.Equal(choices.Processing, blk.Status())
  1575  
  1576  	require.NoError(te.Chits(context.Background(), vdr1, *queryRequestID, blk.ID(), blk.ID(), blk.ID()))
  1577  	require.Equal(choices.Accepted, blk.Status())
  1578  }
  1579  
  1580  func TestEngineBuildBlockLimit(t *testing.T) {
  1581  	require := require.New(t)
  1582  
  1583  	engCfg := DefaultConfig(t)
  1584  	engCfg.Params.K = 1
  1585  	engCfg.Params.AlphaPreference = 1
  1586  	engCfg.Params.AlphaConfidence = 1
  1587  	engCfg.Params.OptimalProcessing = 1
  1588  
  1589  	vals := validators.NewManager()
  1590  	engCfg.Validators = vals
  1591  
  1592  	vdr := ids.GenerateTestNodeID()
  1593  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr, nil, ids.Empty, 1))
  1594  
  1595  	sender := &common.SenderTest{T: t}
  1596  	engCfg.Sender = sender
  1597  	sender.Default(true)
  1598  
  1599  	vm := &block.TestVM{}
  1600  	vm.T = t
  1601  	engCfg.VM = vm
  1602  
  1603  	vm.Default(true)
  1604  	vm.CantSetState = false
  1605  	vm.CantSetPreference = false
  1606  
  1607  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
  1608  		return snowmantest.GenesisID, nil
  1609  	}
  1610  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1611  		require.Equal(snowmantest.GenesisID, blkID)
  1612  		return snowmantest.Genesis, nil
  1613  	}
  1614  
  1615  	te, err := New(engCfg)
  1616  	require.NoError(err)
  1617  
  1618  	require.NoError(te.Start(context.Background(), 0))
  1619  
  1620  	vm.GetBlockF = nil
  1621  	vm.LastAcceptedF = nil
  1622  
  1623  	blks := snowmantest.BuildDescendants(snowmantest.Genesis, 2)
  1624  	blk0 := blks[0]
  1625  
  1626  	var (
  1627  		queried bool
  1628  		reqID   uint32
  1629  	)
  1630  	sender.SendPushQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], rID uint32, _ []byte, _ uint64) {
  1631  		reqID = rID
  1632  		require.False(queried)
  1633  		queried = true
  1634  		vdrSet := set.Of(vdr)
  1635  		require.Equal(vdrSet, inVdrs)
  1636  	}
  1637  
  1638  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1639  		switch blkID {
  1640  		case snowmantest.GenesisID:
  1641  			return snowmantest.Genesis, nil
  1642  		default:
  1643  			return nil, errUnknownBlock
  1644  		}
  1645  	}
  1646  
  1647  	blkToReturn := 0
  1648  	vm.BuildBlockF = func(context.Context) (snowman.Block, error) {
  1649  		require.Less(blkToReturn, len(blks))
  1650  		blk := blks[blkToReturn]
  1651  		blkToReturn++
  1652  		return blk, nil
  1653  	}
  1654  	require.NoError(te.Notify(context.Background(), common.PendingTxs))
  1655  
  1656  	require.True(queried)
  1657  
  1658  	queried = false
  1659  	require.NoError(te.Notify(context.Background(), common.PendingTxs))
  1660  
  1661  	require.False(queried)
  1662  
  1663  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1664  		switch blkID {
  1665  		case snowmantest.GenesisID:
  1666  			return snowmantest.Genesis, nil
  1667  		case blk0.ID():
  1668  			return blk0, nil
  1669  		default:
  1670  			return nil, errUnknownBlock
  1671  		}
  1672  	}
  1673  
  1674  	require.NoError(te.Chits(context.Background(), vdr, reqID, blk0.ID(), blk0.ID(), blk0.ID()))
  1675  
  1676  	require.True(queried)
  1677  }
  1678  
  1679  func TestEngineDropRejectedBlockOnReceipt(t *testing.T) {
  1680  	require := require.New(t)
  1681  
  1682  	nodeID, _, sender, vm, te := setup(t, DefaultConfig(t))
  1683  
  1684  	// Ignore outbound chits
  1685  	sender.SendChitsF = func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {}
  1686  
  1687  	acceptedBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1688  	rejectedChain := snowmantest.BuildDescendants(snowmantest.Genesis, 2)
  1689  	vm.ParseBlockF = MakeParseBlockF(
  1690  		[]*snowmantest.Block{
  1691  			snowmantest.Genesis,
  1692  			acceptedBlk,
  1693  		},
  1694  		rejectedChain,
  1695  	)
  1696  	vm.GetBlockF = MakeGetBlockF([]*snowmantest.Block{
  1697  		snowmantest.Genesis,
  1698  		acceptedBlk,
  1699  	})
  1700  
  1701  	// Track outbound queries
  1702  	var queryRequestIDs []uint32
  1703  	sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, _ ids.ID, _ uint64) {
  1704  		require.Equal(set.Of(nodeID), nodeIDs)
  1705  		queryRequestIDs = append(queryRequestIDs, requestID)
  1706  	}
  1707  
  1708  	// Issue [acceptedBlk] to the engine. This
  1709  	require.NoError(te.PushQuery(context.Background(), nodeID, 0, acceptedBlk.Bytes(), acceptedBlk.Height()))
  1710  	require.Len(queryRequestIDs, 1)
  1711  
  1712  	// Vote for [acceptedBlk] and cause it to be accepted.
  1713  	require.NoError(te.Chits(context.Background(), nodeID, queryRequestIDs[0], acceptedBlk.ID(), acceptedBlk.ID(), acceptedBlk.ID()))
  1714  	require.Len(queryRequestIDs, 1) // Shouldn't have caused another query
  1715  	require.Equal(choices.Accepted, acceptedBlk.Status())
  1716  
  1717  	// Attempt to issue rejectedChain[1] to the engine. This should be dropped
  1718  	// because the engine knows it has rejected it's parent rejectedChain[0].
  1719  	require.NoError(te.PushQuery(context.Background(), nodeID, 0, rejectedChain[1].Bytes(), acceptedBlk.Height()))
  1720  	require.Len(queryRequestIDs, 1) // Shouldn't have caused another query
  1721  	require.Zero(te.blkReqs.Len())
  1722  }
  1723  
  1724  // Test that the node will not gossip a block that isn't preferred.
  1725  func TestEngineNonPreferredAmplification(t *testing.T) {
  1726  	require := require.New(t)
  1727  
  1728  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  1729  
  1730  	preferredBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1731  	nonPreferredBlk := snowmantest.BuildChild(snowmantest.Genesis)
  1732  
  1733  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1734  		switch {
  1735  		case bytes.Equal(b, preferredBlk.Bytes()):
  1736  			return preferredBlk, nil
  1737  		case bytes.Equal(b, nonPreferredBlk.Bytes()):
  1738  			return nonPreferredBlk, nil
  1739  		default:
  1740  			require.FailNow(errUnknownBlock.Error())
  1741  			return nil, errUnknownBlock
  1742  		}
  1743  	}
  1744  
  1745  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1746  		switch blkID {
  1747  		case snowmantest.GenesisID:
  1748  			return snowmantest.Genesis, nil
  1749  		default:
  1750  			return nil, errUnknownBlock
  1751  		}
  1752  	}
  1753  
  1754  	sender.SendPushQueryF = func(_ context.Context, _ set.Set[ids.NodeID], _ uint32, blkBytes []byte, requestedHeight uint64) {
  1755  		require.NotEqual(nonPreferredBlk.Bytes(), blkBytes)
  1756  		require.Equal(uint64(1), requestedHeight)
  1757  	}
  1758  	sender.SendPullQueryF = func(_ context.Context, _ set.Set[ids.NodeID], _ uint32, blkID ids.ID, requestedHeight uint64) {
  1759  		require.NotEqual(nonPreferredBlk.ID(), blkID)
  1760  		require.Equal(uint64(1), requestedHeight)
  1761  	}
  1762  
  1763  	require.NoError(te.Put(context.Background(), vdr, 0, preferredBlk.Bytes()))
  1764  
  1765  	require.NoError(te.Put(context.Background(), vdr, 0, nonPreferredBlk.Bytes()))
  1766  }
  1767  
  1768  // Test that in the following scenario, if block B fails verification, votes
  1769  // will still be bubbled through to the valid block A. This is a regression test
  1770  // to ensure that the consensus engine correctly handles the case that votes can
  1771  // be bubbled correctly through a block that cannot pass verification until one
  1772  // of its ancestors has been marked as accepted.
  1773  //
  1774  //	G
  1775  //	|
  1776  //	A
  1777  //	|
  1778  //	B
  1779  func TestEngineBubbleVotesThroughInvalidBlock(t *testing.T) {
  1780  	require := require.New(t)
  1781  
  1782  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  1783  	expectedVdrSet := set.Of(vdr)
  1784  
  1785  	blk1 := snowmantest.BuildChild(snowmantest.Genesis)
  1786  	// blk2 cannot pass verification until [blk1] has been marked as accepted.
  1787  	blk2 := snowmantest.BuildChild(blk1)
  1788  	blk2.VerifyV = errInvalid
  1789  
  1790  	// The VM should be able to parse [blk1] and [blk2]
  1791  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1792  		switch {
  1793  		case bytes.Equal(b, blk1.Bytes()):
  1794  			return blk1, nil
  1795  		case bytes.Equal(b, blk2.Bytes()):
  1796  			return blk2, nil
  1797  		default:
  1798  			require.FailNow(errUnknownBlock.Error())
  1799  			return nil, errUnknownBlock
  1800  		}
  1801  	}
  1802  
  1803  	// for now, this VM should only be able to retrieve [Genesis] from storage
  1804  	// this "GetBlockF" will be updated after blocks are verified/accepted
  1805  	// in the following tests
  1806  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1807  		switch blkID {
  1808  		case snowmantest.GenesisID:
  1809  			return snowmantest.Genesis, nil
  1810  		default:
  1811  			return nil, errUnknownBlock
  1812  		}
  1813  	}
  1814  
  1815  	asked := new(bool)
  1816  	reqID := new(uint32)
  1817  	sender.SendGetF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, blkID ids.ID) {
  1818  		*reqID = requestID
  1819  		require.False(*asked)
  1820  		require.Equal(blk1.ID(), blkID)
  1821  		require.Equal(vdr, inVdr)
  1822  		*asked = true
  1823  	}
  1824  	sender.CantSendChits = false
  1825  
  1826  	// This engine receives a Gossip message for [blk2] which was "unknown" in this engine.
  1827  	// The engine thus learns about its ancestor [blk1] and should send a Get request for it.
  1828  	// (see above for expected "Get" request)
  1829  	require.NoError(te.PushQuery(context.Background(), vdr, 0, blk2.Bytes(), 0))
  1830  	require.True(*asked)
  1831  
  1832  	// Prepare to PullQuery [blk1] after our Get request is fulfilled. We should not PullQuery
  1833  	// [blk2] since it currently fails verification.
  1834  	queried := new(bool)
  1835  	queryRequestID := new(uint32)
  1836  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  1837  		require.False(*queried)
  1838  		*queried = true
  1839  
  1840  		*queryRequestID = requestID
  1841  		vdrSet := set.Of(vdr)
  1842  		require.Equal(vdrSet, inVdrs)
  1843  		require.Equal(blk1.ID(), blkID)
  1844  		require.Equal(uint64(1), requestedHeight)
  1845  	}
  1846  	// This engine now handles the response to the "Get" request. This should cause [blk1] to be issued
  1847  	// which will result in attempting to issue [blk2]. However, [blk2] should fail verification and be dropped.
  1848  	// By issuing [blk1], this node should fire a "PullQuery" request for [blk1].
  1849  	// (see above for expected "PullQuery" request)
  1850  	require.NoError(te.Put(context.Background(), vdr, *reqID, blk1.Bytes()))
  1851  	require.True(*asked)
  1852  	require.True(*queried, "Didn't query the newly issued blk1")
  1853  
  1854  	// now [blk1] is verified, vm can return it
  1855  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1856  		switch blkID {
  1857  		case snowmantest.GenesisID:
  1858  			return snowmantest.Genesis, nil
  1859  		case blk1.ID():
  1860  			return blk1, nil
  1861  		default:
  1862  			return nil, errUnknownBlock
  1863  		}
  1864  	}
  1865  
  1866  	sendReqID := new(uint32)
  1867  	reqVdr := new(ids.NodeID)
  1868  	// Update GetF to produce a more detailed error message in the case that receiving a Chits
  1869  	// message causes us to send another Get request.
  1870  	sender.SendGetF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, blkID ids.ID) {
  1871  		require.Equal(blk2.ID(), blkID)
  1872  
  1873  		*sendReqID = requestID
  1874  		*reqVdr = inVdr
  1875  	}
  1876  
  1877  	// Now we are expecting a Chits message, and we receive it for [blk2]
  1878  	// instead of [blk1]. This will cause the node to again request [blk2].
  1879  	require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk2.ID(), blk1.ID(), blk2.ID()))
  1880  
  1881  	// The votes should be bubbled through [blk2] despite the fact that it is
  1882  	// failing verification.
  1883  	require.NoError(te.Put(context.Background(), *reqVdr, *sendReqID, blk2.Bytes()))
  1884  
  1885  	// The vote should be bubbled through [blk2], such that [blk1] gets marked as Accepted.
  1886  	require.Equal(choices.Accepted, blk1.Status())
  1887  	require.Equal(choices.Processing, blk2.Status())
  1888  
  1889  	// Now that [blk1] has been marked as Accepted, [blk2] can pass verification.
  1890  	blk2.VerifyV = nil
  1891  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1892  		switch blkID {
  1893  		case snowmantest.GenesisID:
  1894  			return snowmantest.Genesis, nil
  1895  		case blk1.ID():
  1896  			return blk1, nil
  1897  		case blk2.ID():
  1898  			return blk2, nil
  1899  		default:
  1900  			return nil, errUnknownBlock
  1901  		}
  1902  	}
  1903  
  1904  	*queried = false
  1905  	// Prepare to PullQuery [blk2] after receiving a Gossip message with [blk2].
  1906  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  1907  		require.False(*queried)
  1908  		*queried = true
  1909  		*queryRequestID = requestID
  1910  		require.Equal(expectedVdrSet, inVdrs)
  1911  		require.Equal(blk2.ID(), blkID)
  1912  		require.Equal(uint64(2), requestedHeight)
  1913  	}
  1914  	// Expect that the Engine will send a PullQuery after receiving this Gossip message for [blk2].
  1915  	require.NoError(te.PushQuery(context.Background(), vdr, 0, blk2.Bytes(), 0))
  1916  	require.True(*queried)
  1917  
  1918  	// After a single vote for [blk2], it should be marked as accepted.
  1919  	require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk2.ID(), blk1.ID(), blk2.ID()))
  1920  	require.Equal(choices.Accepted, blk2.Status())
  1921  }
  1922  
  1923  // Test that in the following scenario, if block B fails verification, votes
  1924  // will still be bubbled through from block C to the valid block A. This is a
  1925  // regression test to ensure that the consensus engine correctly handles the
  1926  // case that votes can be bubbled correctly through a chain that cannot pass
  1927  // verification until one of its ancestors has been marked as accepted.
  1928  //
  1929  //	G
  1930  //	|
  1931  //	A
  1932  //	|
  1933  //	B
  1934  //	|
  1935  //	C
  1936  func TestEngineBubbleVotesThroughInvalidChain(t *testing.T) {
  1937  	require := require.New(t)
  1938  
  1939  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  1940  	expectedVdrSet := set.Of(vdr)
  1941  
  1942  	blk1 := snowmantest.BuildChild(snowmantest.Genesis)
  1943  	// blk2 cannot pass verification until [blk1] has been marked as accepted.
  1944  	blk2 := snowmantest.BuildChild(blk1)
  1945  	blk2.VerifyV = errInvalid
  1946  	blk3 := snowmantest.BuildChild(blk2)
  1947  
  1948  	// The VM should be able to parse [blk1], [blk2], and [blk3]
  1949  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  1950  		switch {
  1951  		case bytes.Equal(b, blk1.Bytes()):
  1952  			return blk1, nil
  1953  		case bytes.Equal(b, blk2.Bytes()):
  1954  			return blk2, nil
  1955  		case bytes.Equal(b, blk3.Bytes()):
  1956  			return blk3, nil
  1957  		default:
  1958  			require.FailNow(errUnknownBlock.Error())
  1959  			return nil, errUnknownBlock
  1960  		}
  1961  	}
  1962  
  1963  	// The VM should be able to retrieve [Genesis] and [blk1] from storage
  1964  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  1965  		switch blkID {
  1966  		case snowmantest.GenesisID:
  1967  			return snowmantest.Genesis, nil
  1968  		case blk1.ID():
  1969  			return blk1, nil
  1970  		default:
  1971  			return nil, errUnknownBlock
  1972  		}
  1973  	}
  1974  
  1975  	asked := new(bool)
  1976  	reqID := new(uint32)
  1977  	sender.SendGetF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, blkID ids.ID) {
  1978  		*reqID = requestID
  1979  		require.False(*asked)
  1980  		require.Equal(blk2.ID(), blkID)
  1981  		require.Equal(vdr, inVdr)
  1982  		*asked = true
  1983  	}
  1984  	sender.CantSendChits = false
  1985  
  1986  	// Receive Gossip message for [blk3] first and expect the sender to issue a
  1987  	// Get request for its ancestor: [blk2].
  1988  	require.NoError(te.PushQuery(context.Background(), vdr, 0, blk3.Bytes(), 0))
  1989  	require.True(*asked)
  1990  
  1991  	// Prepare to PullQuery [blk1] after our request for [blk2] is fulfilled.
  1992  	// We should not PullQuery [blk2] since it currently fails verification.
  1993  	// We should not PullQuery [blk3] because [blk2] wasn't issued.
  1994  	queried := new(bool)
  1995  	queryRequestID := new(uint32)
  1996  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  1997  		require.False(*queried)
  1998  		*queried = true
  1999  		*queryRequestID = requestID
  2000  		require.Equal(expectedVdrSet, inVdrs)
  2001  		require.Equal(blk1.ID(), blkID)
  2002  		require.Equal(uint64(1), requestedHeight)
  2003  	}
  2004  
  2005  	// Answer the request, this should result in [blk1] being issued as well.
  2006  	require.NoError(te.Put(context.Background(), vdr, *reqID, blk2.Bytes()))
  2007  	require.True(*queried)
  2008  
  2009  	sendReqID := new(uint32)
  2010  	reqVdr := new(ids.NodeID)
  2011  	// Update GetF to produce a more detailed error message in the case that receiving a Chits
  2012  	// message causes us to send another Get request.
  2013  	sender.SendGetF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, blkID ids.ID) {
  2014  		switch blkID {
  2015  		case blk1.ID():
  2016  			require.FailNow("Unexpectedly sent a Get request for blk1")
  2017  		case blk2.ID():
  2018  			t.Logf("sending get for blk2 with %d", requestID)
  2019  			*sendReqID = requestID
  2020  			*reqVdr = inVdr
  2021  			return
  2022  		case blk3.ID():
  2023  			t.Logf("sending get for blk3 with %d", requestID)
  2024  			*sendReqID = requestID
  2025  			*reqVdr = inVdr
  2026  			return
  2027  		default:
  2028  			require.FailNow("Unexpectedly sent a Get request for unknown block")
  2029  		}
  2030  	}
  2031  
  2032  	// Now we are expecting a Chits message and we receive it for [blk3].
  2033  	// This will cause the node to again request [blk3].
  2034  	require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk3.ID(), blk1.ID(), blk3.ID()))
  2035  
  2036  	// Drop the re-request for [blk3] to cause the poll to terminate. The votes
  2037  	// should be bubbled through [blk3] despite the fact that it hasn't been
  2038  	// issued.
  2039  	require.NoError(te.GetFailed(context.Background(), *reqVdr, *sendReqID))
  2040  
  2041  	// The vote should be bubbled through [blk3] and [blk2] such that [blk1]
  2042  	// gets marked as Accepted.
  2043  	require.Equal(choices.Accepted, blk1.Status())
  2044  }
  2045  
  2046  func TestEngineBuildBlockWithCachedNonVerifiedParent(t *testing.T) {
  2047  	require := require.New(t)
  2048  
  2049  	vdr, _, sender, vm, te := setup(t, DefaultConfig(t))
  2050  
  2051  	sender.Default(true)
  2052  
  2053  	grandParentBlk := snowmantest.BuildChild(snowmantest.Genesis)
  2054  
  2055  	parentBlkA := snowmantest.BuildChild(grandParentBlk)
  2056  	parentBlkA.VerifyV = errInvalid
  2057  
  2058  	// Note that [parentBlkB] has the same [ID()] as [parentBlkA];
  2059  	// it's a different instantiation of the same block.
  2060  	parentBlkB := *parentBlkA
  2061  	parentBlkB.VerifyV = nil
  2062  
  2063  	// Child of [parentBlkA]/[parentBlkB]
  2064  	childBlk := snowmantest.BuildChild(parentBlkA)
  2065  
  2066  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  2067  		require.Equal(grandParentBlk.BytesV, b)
  2068  		return grandParentBlk, nil
  2069  	}
  2070  
  2071  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  2072  		switch blkID {
  2073  		case snowmantest.GenesisID:
  2074  			return snowmantest.Genesis, nil
  2075  		case grandParentBlk.IDV:
  2076  			return grandParentBlk, nil
  2077  		default:
  2078  			return nil, errUnknownBlock
  2079  		}
  2080  	}
  2081  
  2082  	queryRequestGPID := new(uint32)
  2083  	sender.SendPullQueryF = func(_ context.Context, _ set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  2084  		*queryRequestGPID = requestID
  2085  		require.Equal(grandParentBlk.ID(), blkID)
  2086  		require.Equal(uint64(1), requestedHeight)
  2087  	}
  2088  
  2089  	// Give the engine the grandparent
  2090  	require.NoError(te.Put(context.Background(), vdr, 0, grandParentBlk.BytesV))
  2091  
  2092  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  2093  		require.Equal(parentBlkA.BytesV, b)
  2094  		return parentBlkA, nil
  2095  	}
  2096  
  2097  	// Give the node [parentBlkA]/[parentBlkB].
  2098  	// When it's parsed we get [parentBlkA] (not [parentBlkB]).
  2099  	// [parentBlkA] fails verification and gets put into [te.nonVerifiedCache].
  2100  	require.NoError(te.Put(context.Background(), vdr, 0, parentBlkA.BytesV))
  2101  
  2102  	vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
  2103  		require.Equal(parentBlkB.BytesV, b)
  2104  		return &parentBlkB, nil
  2105  	}
  2106  
  2107  	vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
  2108  		switch blkID {
  2109  		case snowmantest.GenesisID:
  2110  			return snowmantest.Genesis, nil
  2111  		case grandParentBlk.IDV:
  2112  			return grandParentBlk, nil
  2113  		case parentBlkB.IDV:
  2114  			return &parentBlkB, nil
  2115  		default:
  2116  			return nil, errUnknownBlock
  2117  		}
  2118  	}
  2119  
  2120  	queryRequestAID := new(uint32)
  2121  	sender.SendPullQueryF = func(_ context.Context, _ set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  2122  		*queryRequestAID = requestID
  2123  		require.Equal(parentBlkA.ID(), blkID)
  2124  		require.Equal(uint64(1), requestedHeight)
  2125  	}
  2126  	sender.CantSendPullQuery = false
  2127  
  2128  	// Give the engine [parentBlkA]/[parentBlkB] again.
  2129  	// This time when we parse it we get [parentBlkB] (not [parentBlkA]).
  2130  	// When we fetch it using [GetBlockF] we get [parentBlkB].
  2131  	// Note that [parentBlkB] doesn't fail verification and is issued into consensus.
  2132  	// This evicts [parentBlkA] from [te.nonVerifiedCache].
  2133  	require.NoError(te.Put(context.Background(), vdr, 0, parentBlkA.BytesV))
  2134  
  2135  	// Give 2 chits for [parentBlkA]/[parentBlkB]
  2136  	require.NoError(te.Chits(context.Background(), vdr, *queryRequestAID, parentBlkB.IDV, grandParentBlk.IDV, parentBlkB.IDV))
  2137  	require.NoError(te.Chits(context.Background(), vdr, *queryRequestGPID, parentBlkB.IDV, grandParentBlk.IDV, parentBlkB.IDV))
  2138  
  2139  	// Assert that the blocks' statuses are correct.
  2140  	// The evicted [parentBlkA] shouldn't be changed.
  2141  	require.Equal(choices.Processing, parentBlkA.Status())
  2142  	require.Equal(choices.Accepted, parentBlkB.Status())
  2143  
  2144  	vm.BuildBlockF = func(context.Context) (snowman.Block, error) {
  2145  		return childBlk, nil
  2146  	}
  2147  
  2148  	sentQuery := new(bool)
  2149  	sender.SendPushQueryF = func(context.Context, set.Set[ids.NodeID], uint32, []byte, uint64) {
  2150  		*sentQuery = true
  2151  	}
  2152  
  2153  	// Should issue a new block and send a query for it.
  2154  	require.NoError(te.Notify(context.Background(), common.PendingTxs))
  2155  	require.True(*sentQuery)
  2156  }
  2157  
  2158  func TestEngineApplyAcceptedFrontierInQueryFailed(t *testing.T) {
  2159  	require := require.New(t)
  2160  
  2161  	engCfg := DefaultConfig(t)
  2162  	engCfg.Params = snowball.Parameters{
  2163  		K:                     1,
  2164  		AlphaPreference:       1,
  2165  		AlphaConfidence:       1,
  2166  		Beta:                  2,
  2167  		ConcurrentRepolls:     1,
  2168  		OptimalProcessing:     1,
  2169  		MaxOutstandingItems:   1,
  2170  		MaxItemProcessingTime: 1,
  2171  	}
  2172  
  2173  	vals := validators.NewManager()
  2174  	engCfg.Validators = vals
  2175  
  2176  	vdr := ids.GenerateTestNodeID()
  2177  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr, nil, ids.Empty, 1))
  2178  
  2179  	sender := &common.SenderTest{T: t}
  2180  	engCfg.Sender = sender
  2181  
  2182  	sender.Default(true)
  2183  
  2184  	vm := &block.TestVM{}
  2185  	vm.T = t
  2186  	engCfg.VM = vm
  2187  
  2188  	vm.Default(true)
  2189  	vm.CantSetState = false
  2190  	vm.CantSetPreference = false
  2191  
  2192  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
  2193  		return snowmantest.GenesisID, nil
  2194  	}
  2195  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
  2196  		require.Equal(snowmantest.GenesisID, id)
  2197  		return snowmantest.Genesis, nil
  2198  	}
  2199  
  2200  	te, err := New(engCfg)
  2201  	require.NoError(err)
  2202  	require.NoError(te.Start(context.Background(), 0))
  2203  
  2204  	vm.LastAcceptedF = nil
  2205  
  2206  	blk := snowmantest.BuildChild(snowmantest.Genesis)
  2207  
  2208  	queryRequestID := new(uint32)
  2209  	sender.SendPushQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkBytes []byte, requestedHeight uint64) {
  2210  		*queryRequestID = requestID
  2211  		require.Contains(inVdrs, vdr)
  2212  		require.Equal(blk.Bytes(), blkBytes)
  2213  		require.Equal(uint64(1), requestedHeight)
  2214  	}
  2215  
  2216  	require.NoError(te.issue(
  2217  		context.Background(),
  2218  		te.Ctx.NodeID,
  2219  		blk,
  2220  		true,
  2221  		te.metrics.issued.WithLabelValues(unknownSource),
  2222  	))
  2223  
  2224  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
  2225  		switch id {
  2226  		case snowmantest.GenesisID:
  2227  			return snowmantest.Genesis, nil
  2228  		case blk.ID():
  2229  			return blk, nil
  2230  		}
  2231  		require.FailNow(errUnknownBlock.Error())
  2232  		return nil, errUnknownBlock
  2233  	}
  2234  
  2235  	require.Equal(choices.Processing, blk.Status())
  2236  
  2237  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  2238  		*queryRequestID = requestID
  2239  		require.Contains(inVdrs, vdr)
  2240  		require.Equal(blk.ID(), blkID)
  2241  		require.Equal(uint64(1), requestedHeight)
  2242  	}
  2243  
  2244  	require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk.ID(), blk.ID(), blk.ID()))
  2245  
  2246  	require.Equal(choices.Processing, blk.Status())
  2247  
  2248  	require.NoError(te.QueryFailed(context.Background(), vdr, *queryRequestID))
  2249  
  2250  	require.Equal(choices.Accepted, blk.Status())
  2251  }
  2252  
  2253  func TestEngineRepollsMisconfiguredSubnet(t *testing.T) {
  2254  	require := require.New(t)
  2255  
  2256  	engCfg := DefaultConfig(t)
  2257  	engCfg.Params = snowball.Parameters{
  2258  		K:                     1,
  2259  		AlphaPreference:       1,
  2260  		AlphaConfidence:       1,
  2261  		Beta:                  1,
  2262  		ConcurrentRepolls:     1,
  2263  		OptimalProcessing:     1,
  2264  		MaxOutstandingItems:   1,
  2265  		MaxItemProcessingTime: 1,
  2266  	}
  2267  
  2268  	// Setup the engine with no validators. When a block is issued, the poll
  2269  	// should fail to be created because there is nobody to poll.
  2270  	vals := validators.NewManager()
  2271  	engCfg.Validators = vals
  2272  
  2273  	sender := &common.SenderTest{T: t}
  2274  	engCfg.Sender = sender
  2275  
  2276  	sender.Default(true)
  2277  
  2278  	vm := &block.TestVM{}
  2279  	vm.T = t
  2280  	engCfg.VM = vm
  2281  
  2282  	vm.Default(true)
  2283  	vm.CantSetState = false
  2284  	vm.CantSetPreference = false
  2285  
  2286  	vm.LastAcceptedF = func(context.Context) (ids.ID, error) {
  2287  		return snowmantest.GenesisID, nil
  2288  	}
  2289  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
  2290  		require.Equal(snowmantest.GenesisID, id)
  2291  		return snowmantest.Genesis, nil
  2292  	}
  2293  
  2294  	te, err := New(engCfg)
  2295  	require.NoError(err)
  2296  	require.NoError(te.Start(context.Background(), 0))
  2297  
  2298  	vm.LastAcceptedF = nil
  2299  
  2300  	blk := snowmantest.BuildChild(snowmantest.Genesis)
  2301  
  2302  	// Issue the block. This shouldn't call the sender, because creating the
  2303  	// poll should fail.
  2304  	require.NoError(te.issue(
  2305  		context.Background(),
  2306  		te.Ctx.NodeID,
  2307  		blk,
  2308  		true,
  2309  		te.metrics.issued.WithLabelValues(unknownSource),
  2310  	))
  2311  
  2312  	// The block should have successfully been added into consensus.
  2313  	require.Equal(1, te.Consensus.NumProcessing())
  2314  
  2315  	// Fix the subnet configuration by adding a validator.
  2316  	vdr := ids.GenerateTestNodeID()
  2317  	require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr, nil, ids.Empty, 1))
  2318  
  2319  	var (
  2320  		queryRequestID uint32
  2321  		queried        bool
  2322  	)
  2323  	sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], requestID uint32, blkID ids.ID, requestedHeight uint64) {
  2324  		queryRequestID = requestID
  2325  		require.Contains(inVdrs, vdr)
  2326  		require.Equal(blk.ID(), blkID)
  2327  		require.Equal(uint64(1), requestedHeight)
  2328  		queried = true
  2329  	}
  2330  
  2331  	// Because there is now a validator that can be queried, gossip should
  2332  	// trigger creation of the poll.
  2333  	require.NoError(te.Gossip(context.Background()))
  2334  	require.True(queried)
  2335  
  2336  	vm.GetBlockF = func(_ context.Context, id ids.ID) (snowman.Block, error) {
  2337  		switch id {
  2338  		case snowmantest.GenesisID:
  2339  			return snowmantest.Genesis, nil
  2340  		case blk.ID():
  2341  			return blk, nil
  2342  		}
  2343  		require.FailNow(errUnknownBlock.Error())
  2344  		return nil, errUnknownBlock
  2345  	}
  2346  
  2347  	// Voting for the block that was issued during the period when the validator
  2348  	// set was misconfigured should result in it being accepted successfully.
  2349  	require.NoError(te.Chits(context.Background(), vdr, queryRequestID, blk.ID(), blk.ID(), blk.ID()))
  2350  	require.Equal(choices.Accepted, blk.Status())
  2351  }
  2352  
  2353  // Full blockchain structure:
  2354  //
  2355  //	  G
  2356  //	 / \
  2357  //	0   3
  2358  //	|   |
  2359  //	1   4
  2360  //	|
  2361  //	2
  2362  //
  2363  // K = 3, Alpha = 2, Beta = 1, ConcurrentRepolls = 1
  2364  //
  2365  // Initial configuration:
  2366  //
  2367  //	G
  2368  //	|
  2369  //	0
  2370  //	|
  2371  //	1
  2372  //	|
  2373  //	2
  2374  //
  2375  // The following is a regression test for a bug where the engine would stall.
  2376  //
  2377  //  1. Poll = 0: Handle a chit for block 1.
  2378  //  2. Poll = 0: Handle a chit for block 2.
  2379  //  3. Poll = 0: Handle a chit for block 3. This will issue a Get request for block 3. This will block on the issuance of block 3.
  2380  //  4. Attempt to issue block 4. This will block on the issuance of block 3.
  2381  //  5. Poll = 1: Handle a chit for block 1.
  2382  //  6. Poll = 1: Handle a chit for block 2.
  2383  //  7. Poll = 1: Handle a chit for block 4. This will block on the issuance of block 4.
  2384  //  8. Issue block 3.
  2385  //     Poll = 0 terminates. This will accept blocks 0 and 1. This will also reject block 3.
  2386  //     Block = 4 will attempt to be delivered, but because it is effectively rejected due to the acceptance of block 1, it will be dropped.
  2387  //     Poll = 1 should terminate and block 2 should be repolled.
  2388  func TestEngineVoteStallRegression(t *testing.T) {
  2389  	require := require.New(t)
  2390  
  2391  	config := DefaultConfig(t)
  2392  	config.Params = snowball.Parameters{
  2393  		K:                     3,
  2394  		AlphaPreference:       2,
  2395  		AlphaConfidence:       2,
  2396  		Beta:                  1,
  2397  		ConcurrentRepolls:     1,
  2398  		OptimalProcessing:     1,
  2399  		MaxOutstandingItems:   1,
  2400  		MaxItemProcessingTime: 1,
  2401  	}
  2402  
  2403  	nodeID0 := ids.GenerateTestNodeID()
  2404  	nodeID1 := ids.GenerateTestNodeID()
  2405  	nodeID2 := ids.GenerateTestNodeID()
  2406  	nodeIDs := []ids.NodeID{nodeID0, nodeID1, nodeID2}
  2407  
  2408  	require.NoError(config.Validators.AddStaker(config.Ctx.SubnetID, nodeID0, nil, ids.Empty, 1))
  2409  	require.NoError(config.Validators.AddStaker(config.Ctx.SubnetID, nodeID1, nil, ids.Empty, 1))
  2410  	require.NoError(config.Validators.AddStaker(config.Ctx.SubnetID, nodeID2, nil, ids.Empty, 1))
  2411  
  2412  	sender := &common.SenderTest{
  2413  		T:          t,
  2414  		SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {},
  2415  	}
  2416  	sender.Default(true)
  2417  	config.Sender = sender
  2418  
  2419  	acceptedChain := snowmantest.BuildDescendants(snowmantest.Genesis, 3)
  2420  	rejectedChain := snowmantest.BuildDescendants(snowmantest.Genesis, 2)
  2421  
  2422  	vm := &block.TestVM{
  2423  		TestVM: common.TestVM{
  2424  			T: t,
  2425  			InitializeF: func(
  2426  				context.Context,
  2427  				*snow.Context,
  2428  				database.Database,
  2429  				[]byte,
  2430  				[]byte,
  2431  				[]byte,
  2432  				chan<- common.Message,
  2433  				[]*common.Fx,
  2434  				common.AppSender,
  2435  			) error {
  2436  				return nil
  2437  			},
  2438  			SetStateF: func(context.Context, snow.State) error {
  2439  				return nil
  2440  			},
  2441  		},
  2442  		ParseBlockF: MakeParseBlockF(
  2443  			[]*snowmantest.Block{snowmantest.Genesis},
  2444  			acceptedChain,
  2445  			rejectedChain,
  2446  		),
  2447  		GetBlockF: MakeGetBlockF(
  2448  			[]*snowmantest.Block{snowmantest.Genesis},
  2449  			acceptedChain,
  2450  		),
  2451  		SetPreferenceF: func(context.Context, ids.ID) error {
  2452  			return nil
  2453  		},
  2454  		LastAcceptedF: MakeLastAcceptedBlockF(
  2455  			snowmantest.Genesis,
  2456  			acceptedChain,
  2457  		),
  2458  	}
  2459  	vm.Default(true)
  2460  	config.VM = vm
  2461  
  2462  	engine, err := New(config)
  2463  	require.NoError(err)
  2464  	require.NoError(engine.Start(context.Background(), 0))
  2465  
  2466  	var pollRequestIDs []uint32
  2467  	sender.SendPullQueryF = func(_ context.Context, polledNodeIDs set.Set[ids.NodeID], requestID uint32, _ ids.ID, _ uint64) {
  2468  		require.Equal(set.Of(nodeIDs...), polledNodeIDs)
  2469  		pollRequestIDs = append(pollRequestIDs, requestID)
  2470  	}
  2471  
  2472  	// Issue block 0.
  2473  	require.NoError(engine.PushQuery(
  2474  		context.Background(),
  2475  		nodeID0,
  2476  		0,
  2477  		acceptedChain[0].Bytes(),
  2478  		0,
  2479  	))
  2480  	require.Len(pollRequestIDs, 1)
  2481  
  2482  	// Issue block 1.
  2483  	require.NoError(engine.PushQuery(
  2484  		context.Background(),
  2485  		nodeID0,
  2486  		0,
  2487  		acceptedChain[1].Bytes(),
  2488  		0,
  2489  	))
  2490  	require.Len(pollRequestIDs, 2)
  2491  
  2492  	// Issue block 2.
  2493  	require.NoError(engine.PushQuery(
  2494  		context.Background(),
  2495  		nodeID0,
  2496  		0,
  2497  		acceptedChain[2].Bytes(),
  2498  		0,
  2499  	))
  2500  	require.Len(pollRequestIDs, 3)
  2501  
  2502  	// Apply votes in poll 0 to the blocks that will be accepted.
  2503  	require.NoError(engine.Chits(
  2504  		context.Background(),
  2505  		nodeID0,
  2506  		pollRequestIDs[0],
  2507  		acceptedChain[1].ID(),
  2508  		acceptedChain[1].ID(),
  2509  		acceptedChain[1].ID(),
  2510  	))
  2511  	require.NoError(engine.Chits(
  2512  		context.Background(),
  2513  		nodeID1,
  2514  		pollRequestIDs[0],
  2515  		acceptedChain[2].ID(),
  2516  		acceptedChain[2].ID(),
  2517  		acceptedChain[2].ID(),
  2518  	))
  2519  
  2520  	// Attempt to apply votes in poll 0 for block 3. This will send a Get
  2521  	// request for block 3 and register the chits as a dependency on block 3.
  2522  	var getBlock3Request *common.Request
  2523  	sender.SendGetF = func(_ context.Context, nodeID ids.NodeID, requestID uint32, blkID ids.ID) {
  2524  		require.Nil(getBlock3Request)
  2525  		require.Equal(nodeID2, nodeID)
  2526  		getBlock3Request = &common.Request{
  2527  			NodeID:    nodeID,
  2528  			RequestID: requestID,
  2529  		}
  2530  		require.Equal(rejectedChain[0].ID(), blkID)
  2531  	}
  2532  
  2533  	require.NoError(engine.Chits(
  2534  		context.Background(),
  2535  		nodeID2,
  2536  		pollRequestIDs[0],
  2537  		rejectedChain[0].ID(),
  2538  		rejectedChain[0].ID(),
  2539  		rejectedChain[0].ID(),
  2540  	))
  2541  	require.NotNil(getBlock3Request)
  2542  
  2543  	// Attempt to issue block 4. This will register a dependency on block 3 for
  2544  	// the issuance of block 4.
  2545  	require.NoError(engine.PushQuery(
  2546  		context.Background(),
  2547  		nodeID0,
  2548  		0,
  2549  		rejectedChain[1].Bytes(),
  2550  		0,
  2551  	))
  2552  	require.Len(pollRequestIDs, 3)
  2553  
  2554  	// Apply votes in poll 1 that will cause blocks 3 and 4 to be rejected once
  2555  	// poll 0 finishes.
  2556  	require.NoError(engine.Chits(
  2557  		context.Background(),
  2558  		nodeID0,
  2559  		pollRequestIDs[1],
  2560  		acceptedChain[1].ID(),
  2561  		acceptedChain[1].ID(),
  2562  		acceptedChain[1].ID(),
  2563  	))
  2564  	require.NoError(engine.Chits(
  2565  		context.Background(),
  2566  		nodeID1,
  2567  		pollRequestIDs[1],
  2568  		acceptedChain[2].ID(),
  2569  		acceptedChain[2].ID(),
  2570  		acceptedChain[2].ID(),
  2571  	))
  2572  	require.NoError(engine.Chits(
  2573  		context.Background(),
  2574  		nodeID2,
  2575  		pollRequestIDs[1],
  2576  		rejectedChain[1].ID(),
  2577  		rejectedChain[1].ID(),
  2578  		rejectedChain[1].ID(),
  2579  	))
  2580  
  2581  	// Provide block 3.
  2582  	// This will cause poll 0 to terminate and accept blocks 0 and 1.
  2583  	// Then the engine will attempt to deliver block 4, but because block 1 is
  2584  	// accepted, block 4 will be dropped.
  2585  	// Then poll 1 should terminate because block 4 was dropped.
  2586  	vm.GetBlockF = MakeGetBlockF(
  2587  		[]*snowmantest.Block{snowmantest.Genesis},
  2588  		acceptedChain,
  2589  		rejectedChain,
  2590  	)
  2591  
  2592  	require.NoError(engine.Put(
  2593  		context.Background(),
  2594  		getBlock3Request.NodeID,
  2595  		getBlock3Request.RequestID,
  2596  		rejectedChain[0].Bytes(),
  2597  	))
  2598  	require.Equal(choices.Accepted, acceptedChain[0].Status())
  2599  	require.Equal(choices.Accepted, acceptedChain[1].Status())
  2600  	require.Equal(choices.Processing, acceptedChain[2].Status())
  2601  	require.Equal(choices.Rejected, rejectedChain[0].Status())
  2602  
  2603  	// Then engine should issue as many queries as needed to confirm block 2.
  2604  	for i := 2; i < len(pollRequestIDs); i++ {
  2605  		for _, nodeID := range nodeIDs {
  2606  			require.NoError(engine.Chits(
  2607  				context.Background(),
  2608  				nodeID,
  2609  				pollRequestIDs[i],
  2610  				acceptedChain[2].ID(),
  2611  				acceptedChain[2].ID(),
  2612  				acceptedChain[2].ID(),
  2613  			))
  2614  		}
  2615  	}
  2616  	require.Equal(choices.Accepted, acceptedChain[0].Status())
  2617  	require.Equal(choices.Accepted, acceptedChain[1].Status())
  2618  	require.Equal(choices.Accepted, acceptedChain[2].Status())
  2619  	require.Equal(choices.Rejected, rejectedChain[0].Status())
  2620  }
  2621  
  2622  // When a voter is registered with multiple dependencies, the engine must not
  2623  // execute the voter until all of the dependencies have been resolved; even if
  2624  // one of the dependencies has been abandoned.
  2625  func TestEngineEarlyTerminateVoterRegression(t *testing.T) {
  2626  	require := require.New(t)
  2627  
  2628  	config := DefaultConfig(t)
  2629  	nodeID := ids.GenerateTestNodeID()
  2630  	require.NoError(config.Validators.AddStaker(config.Ctx.SubnetID, nodeID, nil, ids.Empty, 1))
  2631  
  2632  	sender := &common.SenderTest{
  2633  		T:          t,
  2634  		SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {},
  2635  	}
  2636  	sender.Default(true)
  2637  	config.Sender = sender
  2638  
  2639  	chain := snowmantest.BuildDescendants(snowmantest.Genesis, 3)
  2640  	vm := &block.TestVM{
  2641  		TestVM: common.TestVM{
  2642  			T: t,
  2643  			InitializeF: func(
  2644  				context.Context,
  2645  				*snow.Context,
  2646  				database.Database,
  2647  				[]byte,
  2648  				[]byte,
  2649  				[]byte,
  2650  				chan<- common.Message,
  2651  				[]*common.Fx,
  2652  				common.AppSender,
  2653  			) error {
  2654  				return nil
  2655  			},
  2656  			SetStateF: func(context.Context, snow.State) error {
  2657  				return nil
  2658  			},
  2659  		},
  2660  		ParseBlockF: MakeParseBlockF(
  2661  			[]*snowmantest.Block{snowmantest.Genesis},
  2662  			chain,
  2663  		),
  2664  		GetBlockF: MakeGetBlockF(
  2665  			[]*snowmantest.Block{snowmantest.Genesis},
  2666  		),
  2667  		SetPreferenceF: func(context.Context, ids.ID) error {
  2668  			return nil
  2669  		},
  2670  		LastAcceptedF: MakeLastAcceptedBlockF(
  2671  			snowmantest.Genesis,
  2672  			chain,
  2673  		),
  2674  	}
  2675  	vm.Default(true)
  2676  	config.VM = vm
  2677  
  2678  	engine, err := New(config)
  2679  	require.NoError(err)
  2680  	require.NoError(engine.Start(context.Background(), 0))
  2681  
  2682  	var pollRequestIDs []uint32
  2683  	sender.SendPullQueryF = func(_ context.Context, polledNodeIDs set.Set[ids.NodeID], requestID uint32, _ ids.ID, _ uint64) {
  2684  		require.Equal(set.Of(nodeID), polledNodeIDs)
  2685  		pollRequestIDs = append(pollRequestIDs, requestID)
  2686  	}
  2687  
  2688  	getRequestIDs := make(map[ids.ID]uint32)
  2689  	sender.SendGetF = func(_ context.Context, requestedNodeID ids.NodeID, requestID uint32, blkID ids.ID) {
  2690  		require.Equal(nodeID, requestedNodeID)
  2691  		getRequestIDs[blkID] = requestID
  2692  	}
  2693  
  2694  	// Issue block 0 to trigger poll 0.
  2695  	require.NoError(engine.PushQuery(
  2696  		context.Background(),
  2697  		nodeID,
  2698  		0,
  2699  		chain[0].Bytes(),
  2700  		0,
  2701  	))
  2702  	require.Len(pollRequestIDs, 1)
  2703  	require.Empty(getRequestIDs)
  2704  
  2705  	// Update GetBlock to return, the newly issued, block 0. This is needed to
  2706  	// enable the issuance of block 1.
  2707  	vm.GetBlockF = MakeGetBlockF(
  2708  		[]*snowmantest.Block{snowmantest.Genesis},
  2709  		chain[:1],
  2710  	)
  2711  
  2712  	// Vote for block 2 or block 1 in poll 0. This should trigger Get requests
  2713  	// for both block 2 and block 1.
  2714  	require.NoError(engine.Chits(
  2715  		context.Background(),
  2716  		nodeID,
  2717  		pollRequestIDs[0],
  2718  		chain[2].ID(),
  2719  		chain[1].ID(),
  2720  		snowmantest.GenesisID,
  2721  	))
  2722  	require.Len(pollRequestIDs, 1)
  2723  	require.Contains(getRequestIDs, chain[1].ID())
  2724  	require.Contains(getRequestIDs, chain[2].ID())
  2725  
  2726  	// Mark the request for block 2 as failed. This should not cause the poll to
  2727  	// be applied as there is still an outstanding request for block 1.
  2728  	require.NoError(engine.GetFailed(
  2729  		context.Background(),
  2730  		nodeID,
  2731  		getRequestIDs[chain[2].ID()],
  2732  	))
  2733  	require.Len(pollRequestIDs, 1)
  2734  
  2735  	// Issue block 1. This should cause the poll to be applied to both block 0
  2736  	// and block 1.
  2737  	require.NoError(engine.Put(
  2738  		context.Background(),
  2739  		nodeID,
  2740  		getRequestIDs[chain[1].ID()],
  2741  		chain[1].Bytes(),
  2742  	))
  2743  	// Because Put added a new preferred block to the chain, a new poll will be
  2744  	// created.
  2745  	require.Len(pollRequestIDs, 2)
  2746  	require.Equal(choices.Accepted, chain[0].Status())
  2747  	require.Equal(choices.Accepted, chain[1].Status())
  2748  	// Block 2 still hasn't been issued, so it's status should remain
  2749  	// Processing.
  2750  	require.Equal(choices.Processing, chain[2].Status())
  2751  }
  2752  
  2753  // Voting for an unissued cached block that fails verification should not
  2754  // register any dependencies.
  2755  //
  2756  // Full blockchain structure:
  2757  //
  2758  //	  Genesis
  2759  //	 /       \
  2760  //	0         2
  2761  //	|         |
  2762  //	1         3
  2763  //
  2764  // We first issue block 2, and then block 3 fails verification. This causes
  2765  // block 3 to be added to the invalid blocks cache.
  2766  //
  2767  // We then issue block 0, issue block 1, and accept block 0.
  2768  //
  2769  // If we then vote for block 3, the vote should be dropped and trigger a repoll
  2770  // which could then be used to accept block 1.
  2771  func TestEngineRegistersInvalidVoterDependencyRegression(t *testing.T) {
  2772  	require := require.New(t)
  2773  
  2774  	config := DefaultConfig(t)
  2775  	nodeID := ids.GenerateTestNodeID()
  2776  	require.NoError(config.Validators.AddStaker(config.Ctx.SubnetID, nodeID, nil, ids.Empty, 1))
  2777  
  2778  	sender := &common.SenderTest{
  2779  		T:          t,
  2780  		SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {},
  2781  	}
  2782  	sender.Default(true)
  2783  	config.Sender = sender
  2784  
  2785  	var (
  2786  		acceptedChain = snowmantest.BuildDescendants(snowmantest.Genesis, 2)
  2787  		rejectedChain = snowmantest.BuildDescendants(snowmantest.Genesis, 2)
  2788  	)
  2789  	rejectedChain[1].VerifyV = errInvalid
  2790  
  2791  	vm := &block.TestVM{
  2792  		TestVM: common.TestVM{
  2793  			T: t,
  2794  			InitializeF: func(
  2795  				context.Context,
  2796  				*snow.Context,
  2797  				database.Database,
  2798  				[]byte,
  2799  				[]byte,
  2800  				[]byte,
  2801  				chan<- common.Message,
  2802  				[]*common.Fx,
  2803  				common.AppSender,
  2804  			) error {
  2805  				return nil
  2806  			},
  2807  			SetStateF: func(context.Context, snow.State) error {
  2808  				return nil
  2809  			},
  2810  		},
  2811  		ParseBlockF: MakeParseBlockF(
  2812  			[]*snowmantest.Block{snowmantest.Genesis},
  2813  			acceptedChain,
  2814  			rejectedChain,
  2815  		),
  2816  		GetBlockF: MakeGetBlockF(
  2817  			[]*snowmantest.Block{snowmantest.Genesis},
  2818  		),
  2819  		SetPreferenceF: func(context.Context, ids.ID) error {
  2820  			return nil
  2821  		},
  2822  		LastAcceptedF: MakeLastAcceptedBlockF(
  2823  			snowmantest.Genesis,
  2824  			acceptedChain,
  2825  			rejectedChain,
  2826  		),
  2827  	}
  2828  	vm.Default(true)
  2829  	config.VM = vm
  2830  
  2831  	engine, err := New(config)
  2832  	require.NoError(err)
  2833  	require.NoError(engine.Start(context.Background(), 0))
  2834  
  2835  	var pollRequestIDs []uint32
  2836  	sender.SendPullQueryF = func(_ context.Context, polledNodeIDs set.Set[ids.NodeID], requestID uint32, _ ids.ID, _ uint64) {
  2837  		require.Equal(set.Of(nodeID), polledNodeIDs)
  2838  		pollRequestIDs = append(pollRequestIDs, requestID)
  2839  	}
  2840  
  2841  	// Issue rejectedChain[0] to consensus.
  2842  	require.NoError(engine.PushQuery(
  2843  		context.Background(),
  2844  		nodeID,
  2845  		0,
  2846  		rejectedChain[0].Bytes(),
  2847  		0,
  2848  	))
  2849  	require.Len(pollRequestIDs, 1)
  2850  
  2851  	// In order to attempt to issue rejectedChain[1], the engine expects the VM
  2852  	// to be willing to provide rejectedChain[0].
  2853  	vm.GetBlockF = MakeGetBlockF(
  2854  		[]*snowmantest.Block{snowmantest.Genesis},
  2855  		rejectedChain[:1],
  2856  	)
  2857  
  2858  	// Attempt to issue rejectedChain[1] which should add it to the invalid
  2859  	// block cache.
  2860  	require.NoError(engine.PushQuery(
  2861  		context.Background(),
  2862  		nodeID,
  2863  		0,
  2864  		rejectedChain[1].Bytes(),
  2865  		0,
  2866  	))
  2867  	require.Len(pollRequestIDs, 1)
  2868  
  2869  	_, wasCached := engine.nonVerifiedCache.Get(rejectedChain[1].ID())
  2870  	require.True(wasCached)
  2871  
  2872  	// Issue acceptedChain[0] to consensus.
  2873  	require.NoError(engine.PushQuery(
  2874  		context.Background(),
  2875  		nodeID,
  2876  		0,
  2877  		acceptedChain[0].Bytes(),
  2878  		0,
  2879  	))
  2880  	// Because acceptedChain[0] isn't initially preferred, a new poll won't be
  2881  	// created.
  2882  	require.Len(pollRequestIDs, 1)
  2883  
  2884  	// In order to vote for acceptedChain[0], the engine expects the VM to be
  2885  	// willing to provide it.
  2886  	vm.GetBlockF = MakeGetBlockF(
  2887  		[]*snowmantest.Block{snowmantest.Genesis},
  2888  		acceptedChain[:1],
  2889  		rejectedChain[:1],
  2890  	)
  2891  
  2892  	// Accept acceptedChain[0] and reject rejectedChain[0].
  2893  	require.NoError(engine.Chits(
  2894  		context.Background(),
  2895  		nodeID,
  2896  		pollRequestIDs[0],
  2897  		acceptedChain[0].ID(),
  2898  		acceptedChain[0].ID(),
  2899  		snowmantest.GenesisID,
  2900  	))
  2901  	// There are no processing blocks, so no new poll should be created.
  2902  	require.Len(pollRequestIDs, 1)
  2903  	require.Equal(choices.Accepted, acceptedChain[0].Status())
  2904  	require.Equal(choices.Rejected, rejectedChain[0].Status())
  2905  
  2906  	// Issue acceptedChain[1] to consensus.
  2907  	require.NoError(engine.PushQuery(
  2908  		context.Background(),
  2909  		nodeID,
  2910  		0,
  2911  		acceptedChain[1].Bytes(),
  2912  		0,
  2913  	))
  2914  	require.Len(pollRequestIDs, 2)
  2915  
  2916  	// Vote for the transitively rejected rejectedChain[1]. This should cause a
  2917  	// repoll.
  2918  	require.NoError(engine.Chits(
  2919  		context.Background(),
  2920  		nodeID,
  2921  		pollRequestIDs[1],
  2922  		rejectedChain[1].ID(),
  2923  		rejectedChain[1].ID(),
  2924  		snowmantest.GenesisID,
  2925  	))
  2926  	require.Len(pollRequestIDs, 3)
  2927  
  2928  	// In order to vote for acceptedChain[1], the engine expects the VM to be
  2929  	// willing to provide it.
  2930  	vm.GetBlockF = MakeGetBlockF(
  2931  		[]*snowmantest.Block{snowmantest.Genesis},
  2932  		acceptedChain,
  2933  		rejectedChain[:1],
  2934  	)
  2935  
  2936  	// Accept acceptedChain[1].
  2937  	require.NoError(engine.Chits(
  2938  		context.Background(),
  2939  		nodeID,
  2940  		pollRequestIDs[2],
  2941  		acceptedChain[1].ID(),
  2942  		acceptedChain[1].ID(),
  2943  		snowmantest.GenesisID,
  2944  	))
  2945  	require.Len(pollRequestIDs, 3)
  2946  	require.Equal(choices.Accepted, acceptedChain[1].Status())
  2947  }
  2948  
  2949  func TestGetProcessingAncestor(t *testing.T) {
  2950  	var (
  2951  		ctx = snowtest.ConsensusContext(
  2952  			snowtest.Context(t, snowtest.PChainID),
  2953  		)
  2954  		issuedBlock   = snowmantest.BuildChild(snowmantest.Genesis)
  2955  		unissuedBlock = snowmantest.BuildChild(issuedBlock)
  2956  	)
  2957  
  2958  	metrics, err := newMetrics(prometheus.NewRegistry())
  2959  	require.NoError(t, err)
  2960  
  2961  	c := &snowman.Topological{}
  2962  	require.NoError(t, c.Initialize(
  2963  		ctx,
  2964  		snowball.DefaultParameters,
  2965  		snowmantest.GenesisID,
  2966  		0,
  2967  		time.Now(),
  2968  	))
  2969  
  2970  	require.NoError(t, c.Add(issuedBlock))
  2971  
  2972  	nonVerifiedAncestors := ancestor.NewTree()
  2973  	nonVerifiedAncestors.Add(unissuedBlock.ID(), unissuedBlock.Parent())
  2974  
  2975  	tests := []struct {
  2976  		name             string
  2977  		engine           *Transitive
  2978  		initialVote      ids.ID
  2979  		expectedAncestor ids.ID
  2980  		expectedFound    bool
  2981  	}{
  2982  		{
  2983  			name: "drop accepted blockID",
  2984  			engine: &Transitive{
  2985  				Config: Config{
  2986  					Ctx: ctx,
  2987  					VM: &block.TestVM{
  2988  						TestVM: common.TestVM{
  2989  							T: t,
  2990  						},
  2991  						GetBlockF: MakeGetBlockF(
  2992  							[]*snowmantest.Block{snowmantest.Genesis},
  2993  						),
  2994  					},
  2995  					Consensus: c,
  2996  				},
  2997  				metrics:          metrics,
  2998  				nonVerifieds:     ancestor.NewTree(),
  2999  				pending:          map[ids.ID]snowman.Block{},
  3000  				nonVerifiedCache: &cache.Empty[ids.ID, snowman.Block]{},
  3001  			},
  3002  			initialVote:      snowmantest.GenesisID,
  3003  			expectedAncestor: ids.Empty,
  3004  			expectedFound:    false,
  3005  		},
  3006  		{
  3007  			name: "return processing blockID",
  3008  			engine: &Transitive{
  3009  				Config: Config{
  3010  					Ctx: ctx,
  3011  					VM: &block.TestVM{
  3012  						TestVM: common.TestVM{
  3013  							T: t,
  3014  						},
  3015  						GetBlockF: MakeGetBlockF(
  3016  							[]*snowmantest.Block{snowmantest.Genesis},
  3017  						),
  3018  					},
  3019  					Consensus: c,
  3020  				},
  3021  				metrics:          metrics,
  3022  				nonVerifieds:     ancestor.NewTree(),
  3023  				pending:          map[ids.ID]snowman.Block{},
  3024  				nonVerifiedCache: &cache.Empty[ids.ID, snowman.Block]{},
  3025  			},
  3026  			initialVote:      issuedBlock.ID(),
  3027  			expectedAncestor: issuedBlock.ID(),
  3028  			expectedFound:    true,
  3029  		},
  3030  		{
  3031  			name: "drop unknown blockID",
  3032  			engine: &Transitive{
  3033  				Config: Config{
  3034  					Ctx: ctx,
  3035  					VM: &block.TestVM{
  3036  						TestVM: common.TestVM{
  3037  							T: t,
  3038  						},
  3039  						GetBlockF: MakeGetBlockF(
  3040  							[]*snowmantest.Block{snowmantest.Genesis},
  3041  						),
  3042  					},
  3043  					Consensus: c,
  3044  				},
  3045  				metrics:          metrics,
  3046  				nonVerifieds:     ancestor.NewTree(),
  3047  				pending:          map[ids.ID]snowman.Block{},
  3048  				nonVerifiedCache: &cache.Empty[ids.ID, snowman.Block]{},
  3049  			},
  3050  			initialVote:      ids.GenerateTestID(),
  3051  			expectedAncestor: ids.Empty,
  3052  			expectedFound:    false,
  3053  		},
  3054  		{
  3055  			name: "apply vote through ancestor tree",
  3056  			engine: &Transitive{
  3057  				Config: Config{
  3058  					Ctx: ctx,
  3059  					VM: &block.TestVM{
  3060  						TestVM: common.TestVM{
  3061  							T: t,
  3062  						},
  3063  						GetBlockF: MakeGetBlockF(
  3064  							[]*snowmantest.Block{snowmantest.Genesis},
  3065  						),
  3066  					},
  3067  					Consensus: c,
  3068  				},
  3069  				metrics:          metrics,
  3070  				nonVerifieds:     nonVerifiedAncestors,
  3071  				pending:          map[ids.ID]snowman.Block{},
  3072  				nonVerifiedCache: &cache.Empty[ids.ID, snowman.Block]{},
  3073  			},
  3074  			initialVote:      unissuedBlock.ID(),
  3075  			expectedAncestor: issuedBlock.ID(),
  3076  			expectedFound:    true,
  3077  		},
  3078  		{
  3079  			name: "apply vote through pending set",
  3080  			engine: &Transitive{
  3081  				Config: Config{
  3082  					Ctx: ctx,
  3083  					VM: &block.TestVM{
  3084  						TestVM: common.TestVM{
  3085  							T: t,
  3086  						},
  3087  						GetBlockF: MakeGetBlockF(
  3088  							[]*snowmantest.Block{snowmantest.Genesis},
  3089  						),
  3090  					},
  3091  					Consensus: c,
  3092  				},
  3093  				metrics:      metrics,
  3094  				nonVerifieds: ancestor.NewTree(),
  3095  				pending: map[ids.ID]snowman.Block{
  3096  					unissuedBlock.ID(): unissuedBlock,
  3097  				},
  3098  				nonVerifiedCache: &cache.Empty[ids.ID, snowman.Block]{},
  3099  			},
  3100  			initialVote:      unissuedBlock.ID(),
  3101  			expectedAncestor: issuedBlock.ID(),
  3102  			expectedFound:    true,
  3103  		},
  3104  	}
  3105  	for _, test := range tests {
  3106  		t.Run(test.name, func(t *testing.T) {
  3107  			require := require.New(t)
  3108  
  3109  			ancestor, found := test.engine.getProcessingAncestor(context.Background(), test.initialVote)
  3110  			require.Equal(test.expectedAncestor, ancestor)
  3111  			require.Equal(test.expectedFound, found)
  3112  		})
  3113  	}
  3114  }
  3115  
  3116  // Test the engine's classification for blocks to either be dropped or try
  3117  // issuance.
  3118  //
  3119  // Full blockchain structure:
  3120  //
  3121  //	    Genesis
  3122  //	   /       \
  3123  //	  0         7
  3124  //	 / \        |
  3125  //	1   4       8
  3126  //	|   |      / \
  3127  //	2   5     9  11
  3128  //	|   |     |
  3129  //	3   6     10
  3130  //
  3131  // Genesis and 0 are accepted.
  3132  // 1 is issued.
  3133  // 5 and 9 are pending.
  3134  //
  3135  // Structure known to engine:
  3136  //
  3137  //	    Genesis
  3138  //	   /
  3139  //	  0
  3140  //	 /
  3141  //	1
  3142  //
  3143  //	    5     9
  3144  func TestShouldIssueBlock(t *testing.T) {
  3145  	var (
  3146  		ctx = snowtest.ConsensusContext(
  3147  			snowtest.Context(t, snowtest.PChainID),
  3148  		)
  3149  		chain0Through3   = snowmantest.BuildDescendants(snowmantest.Genesis, 4)
  3150  		chain4Through6   = snowmantest.BuildDescendants(chain0Through3[0], 3)
  3151  		chain7Through10  = snowmantest.BuildDescendants(snowmantest.Genesis, 4)
  3152  		chain11Through11 = snowmantest.BuildDescendants(chain7Through10[1], 1)
  3153  		blocks           = join(chain0Through3, chain4Through6, chain7Through10, chain11Through11)
  3154  	)
  3155  
  3156  	require.NoError(t, blocks[0].Accept(context.Background()))
  3157  
  3158  	c := &snowman.Topological{}
  3159  	require.NoError(t, c.Initialize(
  3160  		ctx,
  3161  		snowball.DefaultParameters,
  3162  		blocks[0].ID(),
  3163  		blocks[0].Height(),
  3164  		blocks[0].Timestamp(),
  3165  	))
  3166  	require.NoError(t, c.Add(blocks[1]))
  3167  
  3168  	engine := &Transitive{
  3169  		Config: Config{
  3170  			Consensus: c,
  3171  		},
  3172  		pending: map[ids.ID]snowman.Block{
  3173  			blocks[5].ID(): blocks[5],
  3174  			blocks[9].ID(): blocks[9],
  3175  		},
  3176  	}
  3177  
  3178  	tests := []struct {
  3179  		name                string
  3180  		block               snowman.Block
  3181  		expectedShouldIssue bool
  3182  	}{
  3183  		{
  3184  			name:                "genesis",
  3185  			block:               snowmantest.Genesis,
  3186  			expectedShouldIssue: false,
  3187  		},
  3188  		{
  3189  			name:                "last accepted",
  3190  			block:               blocks[0],
  3191  			expectedShouldIssue: false,
  3192  		},
  3193  		{
  3194  			name:                "already processing",
  3195  			block:               blocks[1],
  3196  			expectedShouldIssue: false,
  3197  		},
  3198  		{
  3199  			name:                "next block to enqueue for issuance on top of a processing block",
  3200  			block:               blocks[2],
  3201  			expectedShouldIssue: true,
  3202  		},
  3203  		{
  3204  			name:                "block to enqueue for issuance which depends on another block",
  3205  			block:               blocks[3],
  3206  			expectedShouldIssue: true,
  3207  		},
  3208  		{
  3209  			name:                "next block to enqueue for issuance on top of an accepted block",
  3210  			block:               blocks[4],
  3211  			expectedShouldIssue: true,
  3212  		},
  3213  		{
  3214  			name:                "already pending block",
  3215  			block:               blocks[5],
  3216  			expectedShouldIssue: false,
  3217  		},
  3218  		{
  3219  			name:                "block to enqueue on top of a pending block",
  3220  			block:               blocks[6],
  3221  			expectedShouldIssue: true,
  3222  		},
  3223  		{
  3224  			name:                "block was directly rejected",
  3225  			block:               blocks[7],
  3226  			expectedShouldIssue: false,
  3227  		},
  3228  		{
  3229  			name:                "block was transitively rejected",
  3230  			block:               blocks[8],
  3231  			expectedShouldIssue: false,
  3232  		},
  3233  		{
  3234  			name:                "block was transitively rejected but that is not known and was marked as pending",
  3235  			block:               blocks[9],
  3236  			expectedShouldIssue: false,
  3237  		},
  3238  		{
  3239  			name:                "block was transitively rejected but that is not known and is built on top of pending",
  3240  			block:               blocks[10],
  3241  			expectedShouldIssue: true,
  3242  		},
  3243  		{
  3244  			name:                "block was transitively rejected but that is not known",
  3245  			block:               blocks[11],
  3246  			expectedShouldIssue: true,
  3247  		},
  3248  	}
  3249  	for i, test := range tests {
  3250  		t.Run(fmt.Sprintf("%d %s", i-1, test.name), func(t *testing.T) {
  3251  			shouldIssue := engine.shouldIssueBlock(test.block)
  3252  			require.Equal(t, test.expectedShouldIssue, shouldIssue)
  3253  		})
  3254  	}
  3255  }
  3256  
  3257  // join the provided slices into a single slice.
  3258  //
  3259  // TODO: Use slices.Concat once the minimum go version is 1.22.
  3260  func join[T any](slices ...[]T) []T {
  3261  	size := 0
  3262  	for _, s := range slices {
  3263  		size += len(s)
  3264  	}
  3265  	newSlice := make([]T, 0, size)
  3266  	for _, s := range slices {
  3267  		newSlice = append(newSlice, s...)
  3268  	}
  3269  	return newSlice
  3270  }