github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/network/network.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 "time" 10 11 "github.com/prometheus/client_golang/prometheus" 12 "go.uber.org/zap" 13 14 "github.com/ava-labs/avalanchego/ids" 15 "github.com/ava-labs/avalanchego/network/p2p" 16 "github.com/ava-labs/avalanchego/network/p2p/gossip" 17 "github.com/ava-labs/avalanchego/snow/engine/common" 18 "github.com/ava-labs/avalanchego/snow/validators" 19 "github.com/ava-labs/avalanchego/utils/logging" 20 "github.com/ava-labs/avalanchego/vms/platformvm/txs" 21 "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" 22 ) 23 24 var errMempoolDisabledWithPartialSync = errors.New("mempool is disabled partial syncing") 25 26 type Network struct { 27 *p2p.Network 28 29 log logging.Logger 30 txVerifier TxVerifier 31 mempool *gossipMempool 32 partialSyncPrimaryNetwork bool 33 appSender common.AppSender 34 35 txPushGossiper *gossip.PushGossiper[*txs.Tx] 36 txPushGossipFrequency time.Duration 37 txPullGossiper gossip.Gossiper 38 txPullGossipFrequency time.Duration 39 } 40 41 func New( 42 log logging.Logger, 43 nodeID ids.NodeID, 44 subnetID ids.ID, 45 vdrs validators.State, 46 txVerifier TxVerifier, 47 mempool mempool.Mempool, 48 partialSyncPrimaryNetwork bool, 49 appSender common.AppSender, 50 registerer prometheus.Registerer, 51 config Config, 52 ) (*Network, error) { 53 p2pNetwork, err := p2p.NewNetwork(log, appSender, registerer, "p2p") 54 if err != nil { 55 return nil, err 56 } 57 58 marshaller := txMarshaller{} 59 validators := p2p.NewValidators( 60 p2pNetwork.Peers, 61 log, 62 subnetID, 63 vdrs, 64 config.MaxValidatorSetStaleness, 65 ) 66 txGossipClient := p2pNetwork.NewClient( 67 p2p.TxGossipHandlerID, 68 p2p.WithValidatorSampling(validators), 69 ) 70 txGossipMetrics, err := gossip.NewMetrics(registerer, "tx") 71 if err != nil { 72 return nil, err 73 } 74 75 gossipMempool, err := newGossipMempool( 76 mempool, 77 registerer, 78 log, 79 txVerifier, 80 config.ExpectedBloomFilterElements, 81 config.ExpectedBloomFilterFalsePositiveProbability, 82 config.MaxBloomFilterFalsePositiveProbability, 83 ) 84 if err != nil { 85 return nil, err 86 } 87 88 txPushGossiper, err := gossip.NewPushGossiper[*txs.Tx]( 89 marshaller, 90 gossipMempool, 91 validators, 92 txGossipClient, 93 txGossipMetrics, 94 gossip.BranchingFactor{ 95 StakePercentage: config.PushGossipPercentStake, 96 Validators: config.PushGossipNumValidators, 97 Peers: config.PushGossipNumPeers, 98 }, 99 gossip.BranchingFactor{ 100 Validators: config.PushRegossipNumValidators, 101 Peers: config.PushRegossipNumPeers, 102 }, 103 config.PushGossipDiscardedCacheSize, 104 config.TargetGossipSize, 105 config.PushGossipMaxRegossipFrequency, 106 ) 107 if err != nil { 108 return nil, err 109 } 110 111 var txPullGossiper gossip.Gossiper = gossip.NewPullGossiper[*txs.Tx]( 112 log, 113 marshaller, 114 gossipMempool, 115 txGossipClient, 116 txGossipMetrics, 117 config.PullGossipPollSize, 118 ) 119 120 // Gossip requests are only served if a node is a validator 121 txPullGossiper = gossip.ValidatorGossiper{ 122 Gossiper: txPullGossiper, 123 NodeID: nodeID, 124 Validators: validators, 125 } 126 127 handler := gossip.NewHandler[*txs.Tx]( 128 log, 129 marshaller, 130 gossipMempool, 131 txGossipMetrics, 132 config.TargetGossipSize, 133 ) 134 135 validatorHandler := p2p.NewValidatorHandler( 136 p2p.NewThrottlerHandler( 137 handler, 138 p2p.NewSlidingWindowThrottler( 139 config.PullGossipThrottlingPeriod, 140 config.PullGossipThrottlingLimit, 141 ), 142 log, 143 ), 144 validators, 145 log, 146 ) 147 148 // We allow pushing txs between all peers, but only serve gossip requests 149 // from validators 150 txGossipHandler := txGossipHandler{ 151 appGossipHandler: handler, 152 appRequestHandler: validatorHandler, 153 } 154 155 if err := p2pNetwork.AddHandler(p2p.TxGossipHandlerID, txGossipHandler); err != nil { 156 return nil, err 157 } 158 159 return &Network{ 160 Network: p2pNetwork, 161 log: log, 162 txVerifier: txVerifier, 163 mempool: gossipMempool, 164 partialSyncPrimaryNetwork: partialSyncPrimaryNetwork, 165 appSender: appSender, 166 txPushGossiper: txPushGossiper, 167 txPushGossipFrequency: config.PushGossipFrequency, 168 txPullGossiper: txPullGossiper, 169 txPullGossipFrequency: config.PullGossipFrequency, 170 }, nil 171 } 172 173 func (n *Network) PushGossip(ctx context.Context) { 174 // TODO: Even though the node is running partial sync, we should support 175 // issuing transactions from the RPC. 176 if n.partialSyncPrimaryNetwork { 177 return 178 } 179 180 gossip.Every(ctx, n.log, n.txPushGossiper, n.txPushGossipFrequency) 181 } 182 183 func (n *Network) PullGossip(ctx context.Context) { 184 // If the node is running partial sync, we should not perform any pull 185 // gossip. 186 if n.partialSyncPrimaryNetwork { 187 return 188 } 189 190 gossip.Every(ctx, n.log, n.txPullGossiper, n.txPullGossipFrequency) 191 } 192 193 func (n *Network) AppGossip(ctx context.Context, nodeID ids.NodeID, msgBytes []byte) error { 194 if n.partialSyncPrimaryNetwork { 195 n.log.Debug("dropping AppGossip message", 196 zap.String("reason", "primary network is not being fully synced"), 197 ) 198 return nil 199 } 200 201 return n.Network.AppGossip(ctx, nodeID, msgBytes) 202 } 203 204 func (n *Network) IssueTxFromRPC(tx *txs.Tx) error { 205 // If we are partially syncing the Primary Network, we should not be 206 // maintaining the transaction mempool locally. 207 // 208 // TODO: We should still push the transaction to some peers when partial 209 // syncing. 210 if n.partialSyncPrimaryNetwork { 211 return errMempoolDisabledWithPartialSync 212 } 213 214 if err := n.mempool.Add(tx); err != nil { 215 return err 216 } 217 n.txPushGossiper.Add(tx) 218 return nil 219 }