github.com/MetalBlockchain/metalgo@v1.11.9/vms/avm/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/validators" 19 "github.com/MetalBlockchain/metalgo/utils/logging" 20 "github.com/MetalBlockchain/metalgo/vms/avm/block/executor" 21 "github.com/MetalBlockchain/metalgo/vms/avm/fxs" 22 "github.com/MetalBlockchain/metalgo/vms/avm/txs" 23 "github.com/MetalBlockchain/metalgo/vms/nftfx" 24 "github.com/MetalBlockchain/metalgo/vms/propertyfx" 25 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 26 "github.com/MetalBlockchain/metalgo/vms/txs/mempool" 27 28 xmempool "github.com/MetalBlockchain/metalgo/vms/avm/txs/mempool" 29 ) 30 31 var ( 32 testConfig = Config{ 33 MaxValidatorSetStaleness: time.Second, 34 TargetGossipSize: 1, 35 PushGossipNumValidators: 1, 36 PushGossipNumPeers: 0, 37 PushRegossipNumValidators: 1, 38 PushRegossipNumPeers: 0, 39 PushGossipDiscardedCacheSize: 1, 40 PushGossipMaxRegossipFrequency: time.Second, 41 PushGossipFrequency: time.Second, 42 PullGossipPollSize: 1, 43 PullGossipFrequency: time.Second, 44 PullGossipThrottlingPeriod: time.Second, 45 PullGossipThrottlingLimit: 1, 46 ExpectedBloomFilterElements: 10, 47 ExpectedBloomFilterFalsePositiveProbability: .1, 48 MaxBloomFilterFalsePositiveProbability: .5, 49 } 50 51 errTest = errors.New("test error") 52 ) 53 54 func TestNetworkIssueTxFromRPC(t *testing.T) { 55 type test struct { 56 name string 57 mempoolFunc func(*gomock.Controller) xmempool.Mempool 58 txVerifierFunc func(*gomock.Controller) TxVerifier 59 appSenderFunc func(*gomock.Controller) common.AppSender 60 expectedErr error 61 } 62 63 tests := []test{ 64 { 65 name: "mempool has transaction", 66 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 67 mempool := xmempool.NewMockMempool(ctrl) 68 mempool.EXPECT().Get(gomock.Any()).Return(nil, true) 69 return mempool 70 }, 71 expectedErr: mempool.ErrDuplicateTx, 72 }, 73 { 74 name: "transaction marked as dropped in mempool", 75 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 76 mempool := xmempool.NewMockMempool(ctrl) 77 mempool.EXPECT().Get(gomock.Any()).Return(nil, false) 78 mempool.EXPECT().GetDropReason(gomock.Any()).Return(errTest) 79 return mempool 80 }, 81 expectedErr: errTest, 82 }, 83 { 84 name: "transaction invalid", 85 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 86 mempool := xmempool.NewMockMempool(ctrl) 87 mempool.EXPECT().Get(gomock.Any()).Return(nil, false) 88 mempool.EXPECT().GetDropReason(gomock.Any()).Return(nil) 89 mempool.EXPECT().MarkDropped(gomock.Any(), gomock.Any()) 90 return mempool 91 }, 92 txVerifierFunc: func(ctrl *gomock.Controller) TxVerifier { 93 txVerifier := executor.NewMockManager(ctrl) 94 txVerifier.EXPECT().VerifyTx(gomock.Any()).Return(errTest) 95 return txVerifier 96 }, 97 expectedErr: errTest, 98 }, 99 { 100 name: "can't add transaction to mempool", 101 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 102 mempool := xmempool.NewMockMempool(ctrl) 103 mempool.EXPECT().Get(gomock.Any()).Return(nil, false) 104 mempool.EXPECT().GetDropReason(gomock.Any()).Return(nil) 105 mempool.EXPECT().Add(gomock.Any()).Return(errTest) 106 mempool.EXPECT().MarkDropped(gomock.Any(), gomock.Any()) 107 return mempool 108 }, 109 txVerifierFunc: func(ctrl *gomock.Controller) TxVerifier { 110 txVerifier := executor.NewMockManager(ctrl) 111 txVerifier.EXPECT().VerifyTx(gomock.Any()).Return(nil) 112 return txVerifier 113 }, 114 expectedErr: errTest, 115 }, 116 { 117 name: "happy path", 118 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 119 mempool := xmempool.NewMockMempool(ctrl) 120 mempool.EXPECT().Get(gomock.Any()).Return(nil, false) 121 mempool.EXPECT().GetDropReason(gomock.Any()).Return(nil) 122 mempool.EXPECT().Add(gomock.Any()).Return(nil) 123 mempool.EXPECT().Len().Return(0) 124 mempool.EXPECT().RequestBuildBlock() 125 mempool.EXPECT().Get(gomock.Any()).Return(nil, true).Times(2) 126 return mempool 127 }, 128 txVerifierFunc: func(ctrl *gomock.Controller) TxVerifier { 129 txVerifier := executor.NewMockManager(ctrl) 130 txVerifier.EXPECT().VerifyTx(gomock.Any()).Return(nil) 131 return txVerifier 132 }, 133 appSenderFunc: func(ctrl *gomock.Controller) common.AppSender { 134 appSender := common.NewMockSender(ctrl) 135 appSender.EXPECT().SendAppGossip(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) 136 return appSender 137 }, 138 expectedErr: nil, 139 }, 140 } 141 142 for _, tt := range tests { 143 t.Run(tt.name, func(t *testing.T) { 144 require := require.New(t) 145 ctrl := gomock.NewController(t) 146 147 parser, err := txs.NewParser( 148 []fxs.Fx{ 149 &secp256k1fx.Fx{}, 150 &nftfx.Fx{}, 151 &propertyfx.Fx{}, 152 }, 153 ) 154 require.NoError(err) 155 156 mempoolFunc := func(ctrl *gomock.Controller) xmempool.Mempool { 157 return xmempool.NewMockMempool(ctrl) 158 } 159 if tt.mempoolFunc != nil { 160 mempoolFunc = tt.mempoolFunc 161 } 162 163 txVerifierFunc := func(ctrl *gomock.Controller) TxVerifier { 164 return executor.NewMockManager(ctrl) 165 } 166 if tt.txVerifierFunc != nil { 167 txVerifierFunc = tt.txVerifierFunc 168 } 169 170 appSenderFunc := func(ctrl *gomock.Controller) common.AppSender { 171 return common.NewMockSender(ctrl) 172 } 173 if tt.appSenderFunc != nil { 174 appSenderFunc = tt.appSenderFunc 175 } 176 177 n, err := New( 178 logging.NoLog{}, 179 ids.EmptyNodeID, 180 ids.Empty, 181 &validators.TestState{ 182 GetCurrentHeightF: func(context.Context) (uint64, error) { 183 return 0, nil 184 }, 185 GetValidatorSetF: func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) { 186 return nil, nil 187 }, 188 }, 189 parser, 190 txVerifierFunc(ctrl), 191 mempoolFunc(ctrl), 192 appSenderFunc(ctrl), 193 prometheus.NewRegistry(), 194 testConfig, 195 ) 196 require.NoError(err) 197 err = n.IssueTxFromRPC(&txs.Tx{}) 198 require.ErrorIs(err, tt.expectedErr) 199 200 require.NoError(n.txPushGossiper.Gossip(context.Background())) 201 }) 202 } 203 } 204 205 func TestNetworkIssueTxFromRPCWithoutVerification(t *testing.T) { 206 type test struct { 207 name string 208 mempoolFunc func(*gomock.Controller) xmempool.Mempool 209 appSenderFunc func(*gomock.Controller) common.AppSender 210 expectedErr error 211 } 212 213 tests := []test{ 214 { 215 name: "can't add transaction to mempool", 216 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 217 mempool := xmempool.NewMockMempool(ctrl) 218 mempool.EXPECT().Add(gomock.Any()).Return(errTest) 219 mempool.EXPECT().MarkDropped(gomock.Any(), gomock.Any()) 220 return mempool 221 }, 222 expectedErr: errTest, 223 }, 224 { 225 name: "happy path", 226 mempoolFunc: func(ctrl *gomock.Controller) xmempool.Mempool { 227 mempool := xmempool.NewMockMempool(ctrl) 228 mempool.EXPECT().Get(gomock.Any()).Return(nil, true).Times(2) 229 mempool.EXPECT().Add(gomock.Any()).Return(nil) 230 mempool.EXPECT().Len().Return(0) 231 mempool.EXPECT().RequestBuildBlock() 232 return mempool 233 }, 234 appSenderFunc: func(ctrl *gomock.Controller) common.AppSender { 235 appSender := common.NewMockSender(ctrl) 236 appSender.EXPECT().SendAppGossip(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) 237 return appSender 238 }, 239 expectedErr: nil, 240 }, 241 } 242 243 for _, tt := range tests { 244 t.Run(tt.name, func(t *testing.T) { 245 require := require.New(t) 246 ctrl := gomock.NewController(t) 247 248 parser, err := txs.NewParser( 249 []fxs.Fx{ 250 &secp256k1fx.Fx{}, 251 &nftfx.Fx{}, 252 &propertyfx.Fx{}, 253 }, 254 ) 255 require.NoError(err) 256 257 mempoolFunc := func(ctrl *gomock.Controller) xmempool.Mempool { 258 return xmempool.NewMockMempool(ctrl) 259 } 260 if tt.mempoolFunc != nil { 261 mempoolFunc = tt.mempoolFunc 262 } 263 264 appSenderFunc := func(ctrl *gomock.Controller) common.AppSender { 265 return common.NewMockSender(ctrl) 266 } 267 if tt.appSenderFunc != nil { 268 appSenderFunc = tt.appSenderFunc 269 } 270 271 n, err := New( 272 logging.NoLog{}, 273 ids.EmptyNodeID, 274 ids.Empty, 275 &validators.TestState{ 276 GetCurrentHeightF: func(context.Context) (uint64, error) { 277 return 0, nil 278 }, 279 GetValidatorSetF: func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) { 280 return nil, nil 281 }, 282 }, 283 parser, 284 executor.NewMockManager(ctrl), // Should never verify a tx 285 mempoolFunc(ctrl), 286 appSenderFunc(ctrl), 287 prometheus.NewRegistry(), 288 testConfig, 289 ) 290 require.NoError(err) 291 err = n.IssueTxFromRPCWithoutVerification(&txs.Tx{}) 292 require.ErrorIs(err, tt.expectedErr) 293 294 require.NoError(n.txPushGossiper.Gossip(context.Background())) 295 }) 296 } 297 }