github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/network/network_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 network
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/stretchr/testify/require"
    14  	"go.uber.org/mock/gomock"
    15  
    16  	"github.com/MetalBlockchain/metalgo/ids"
    17  	"github.com/MetalBlockchain/metalgo/snow/engine/common"
    18  	"github.com/MetalBlockchain/metalgo/snow/snowtest"
    19  	"github.com/MetalBlockchain/metalgo/vms/platformvm/txs"
    20  	"github.com/MetalBlockchain/metalgo/vms/txs/mempool"
    21  
    22  	pmempool "github.com/MetalBlockchain/metalgo/vms/platformvm/txs/mempool"
    23  )
    24  
    25  var (
    26  	errTest = errors.New("test error")
    27  
    28  	testConfig = Config{
    29  		MaxValidatorSetStaleness:                    time.Second,
    30  		TargetGossipSize:                            1,
    31  		PushGossipNumValidators:                     1,
    32  		PushGossipNumPeers:                          0,
    33  		PushRegossipNumValidators:                   1,
    34  		PushRegossipNumPeers:                        0,
    35  		PushGossipDiscardedCacheSize:                1,
    36  		PushGossipMaxRegossipFrequency:              time.Second,
    37  		PushGossipFrequency:                         time.Second,
    38  		PullGossipPollSize:                          1,
    39  		PullGossipFrequency:                         time.Second,
    40  		PullGossipThrottlingPeriod:                  time.Second,
    41  		PullGossipThrottlingLimit:                   1,
    42  		ExpectedBloomFilterElements:                 10,
    43  		ExpectedBloomFilterFalsePositiveProbability: .1,
    44  		MaxBloomFilterFalsePositiveProbability:      .5,
    45  	}
    46  )
    47  
    48  var _ TxVerifier = (*testTxVerifier)(nil)
    49  
    50  type testTxVerifier struct {
    51  	err error
    52  }
    53  
    54  func (t testTxVerifier) VerifyTx(*txs.Tx) error {
    55  	return t.err
    56  }
    57  
    58  func TestNetworkIssueTxFromRPC(t *testing.T) {
    59  	tx := &txs.Tx{}
    60  
    61  	type test struct {
    62  		name                      string
    63  		mempoolFunc               func(*gomock.Controller) pmempool.Mempool
    64  		txVerifier                testTxVerifier
    65  		partialSyncPrimaryNetwork bool
    66  		appSenderFunc             func(*gomock.Controller) common.AppSender
    67  		expectedErr               error
    68  	}
    69  
    70  	tests := []test{
    71  		{
    72  			name: "mempool has transaction",
    73  			mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool {
    74  				mempool := pmempool.NewMockMempool(ctrl)
    75  				mempool.EXPECT().Get(gomock.Any()).Return(tx, true)
    76  				return mempool
    77  			},
    78  			appSenderFunc: func(ctrl *gomock.Controller) common.AppSender {
    79  				return common.NewMockSender(ctrl)
    80  			},
    81  			expectedErr: mempool.ErrDuplicateTx,
    82  		},
    83  		{
    84  			name: "transaction marked as dropped in mempool",
    85  			mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool {
    86  				mempool := pmempool.NewMockMempool(ctrl)
    87  				mempool.EXPECT().Get(gomock.Any()).Return(nil, false)
    88  				mempool.EXPECT().GetDropReason(gomock.Any()).Return(errTest)
    89  				return mempool
    90  			},
    91  			appSenderFunc: func(ctrl *gomock.Controller) common.AppSender {
    92  				// Shouldn't gossip the tx
    93  				return common.NewMockSender(ctrl)
    94  			},
    95  			expectedErr: errTest,
    96  		},
    97  		{
    98  			name: "transaction invalid",
    99  			mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool {
   100  				mempool := pmempool.NewMockMempool(ctrl)
   101  				mempool.EXPECT().Get(gomock.Any()).Return(nil, false)
   102  				mempool.EXPECT().GetDropReason(gomock.Any()).Return(nil)
   103  				mempool.EXPECT().MarkDropped(gomock.Any(), gomock.Any())
   104  				return mempool
   105  			},
   106  			txVerifier: testTxVerifier{err: errTest},
   107  			appSenderFunc: func(ctrl *gomock.Controller) common.AppSender {
   108  				// Shouldn't gossip the tx
   109  				return common.NewMockSender(ctrl)
   110  			},
   111  			expectedErr: errTest,
   112  		},
   113  		{
   114  			name: "can't add transaction to mempool",
   115  			mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool {
   116  				mempool := pmempool.NewMockMempool(ctrl)
   117  				mempool.EXPECT().Get(gomock.Any()).Return(nil, false)
   118  				mempool.EXPECT().GetDropReason(gomock.Any()).Return(nil)
   119  				mempool.EXPECT().Add(gomock.Any()).Return(errTest)
   120  				mempool.EXPECT().MarkDropped(gomock.Any(), gomock.Any())
   121  				return mempool
   122  			},
   123  			appSenderFunc: func(ctrl *gomock.Controller) common.AppSender {
   124  				// Shouldn't gossip the tx
   125  				return common.NewMockSender(ctrl)
   126  			},
   127  			expectedErr: errTest,
   128  		},
   129  		{
   130  			name: "mempool is disabled if primary network is not being fully synced",
   131  			mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool {
   132  				return pmempool.NewMockMempool(ctrl)
   133  			},
   134  			partialSyncPrimaryNetwork: true,
   135  			appSenderFunc: func(ctrl *gomock.Controller) common.AppSender {
   136  				return common.NewMockSender(ctrl)
   137  			},
   138  			expectedErr: errMempoolDisabledWithPartialSync,
   139  		},
   140  		{
   141  			name: "happy path",
   142  			mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool {
   143  				mempool := pmempool.NewMockMempool(ctrl)
   144  				mempool.EXPECT().Get(gomock.Any()).Return(nil, false)
   145  				mempool.EXPECT().GetDropReason(gomock.Any()).Return(nil)
   146  				mempool.EXPECT().Add(gomock.Any()).Return(nil)
   147  				mempool.EXPECT().Len().Return(0)
   148  				mempool.EXPECT().RequestBuildBlock(false)
   149  				mempool.EXPECT().Get(gomock.Any()).Return(nil, true).Times(2)
   150  				return mempool
   151  			},
   152  			appSenderFunc: func(ctrl *gomock.Controller) common.AppSender {
   153  				appSender := common.NewMockSender(ctrl)
   154  				appSender.EXPECT().SendAppGossip(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
   155  				return appSender
   156  			},
   157  			expectedErr: nil,
   158  		},
   159  	}
   160  
   161  	for _, tt := range tests {
   162  		t.Run(tt.name, func(t *testing.T) {
   163  			require := require.New(t)
   164  			ctrl := gomock.NewController(t)
   165  
   166  			snowCtx := snowtest.Context(t, ids.Empty)
   167  			n, err := New(
   168  				snowCtx.Log,
   169  				snowCtx.NodeID,
   170  				snowCtx.SubnetID,
   171  				snowCtx.ValidatorState,
   172  				tt.txVerifier,
   173  				tt.mempoolFunc(ctrl),
   174  				tt.partialSyncPrimaryNetwork,
   175  				tt.appSenderFunc(ctrl),
   176  				prometheus.NewRegistry(),
   177  				testConfig,
   178  			)
   179  			require.NoError(err)
   180  
   181  			err = n.IssueTxFromRPC(tx)
   182  			require.ErrorIs(err, tt.expectedErr)
   183  
   184  			require.NoError(n.txPushGossiper.Gossip(context.Background()))
   185  		})
   186  	}
   187  }