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 }