github.com/ava-labs/avalanchego@v1.11.11/vms/avm/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 "time" 9 10 "github.com/prometheus/client_golang/prometheus" 11 12 "github.com/ava-labs/avalanchego/ids" 13 "github.com/ava-labs/avalanchego/network/p2p" 14 "github.com/ava-labs/avalanchego/network/p2p/gossip" 15 "github.com/ava-labs/avalanchego/snow/engine/common" 16 "github.com/ava-labs/avalanchego/snow/validators" 17 "github.com/ava-labs/avalanchego/utils/logging" 18 "github.com/ava-labs/avalanchego/vms/avm/txs" 19 "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" 20 ) 21 22 var ( 23 _ common.AppHandler = (*Network)(nil) 24 _ validators.Connector = (*Network)(nil) 25 ) 26 27 type Network struct { 28 *p2p.Network 29 30 log logging.Logger 31 parser txs.Parser 32 mempool *gossipMempool 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 parser txs.Parser, 47 txVerifier TxVerifier, 48 mempool mempool.Mempool, 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 := &txParser{ 59 parser: parser, 60 } 61 validators := p2p.NewValidators( 62 p2pNetwork.Peers, 63 log, 64 subnetID, 65 vdrs, 66 config.MaxValidatorSetStaleness, 67 ) 68 txGossipClient := p2pNetwork.NewClient( 69 p2p.TxGossipHandlerID, 70 p2p.WithValidatorSampling(validators), 71 ) 72 txGossipMetrics, err := gossip.NewMetrics(registerer, "tx") 73 if err != nil { 74 return nil, err 75 } 76 77 gossipMempool, err := newGossipMempool( 78 mempool, 79 registerer, 80 log, 81 txVerifier, 82 parser, 83 config.ExpectedBloomFilterElements, 84 config.ExpectedBloomFilterFalsePositiveProbability, 85 config.MaxBloomFilterFalsePositiveProbability, 86 ) 87 if err != nil { 88 return nil, err 89 } 90 91 txPushGossiper, err := gossip.NewPushGossiper[*txs.Tx]( 92 marshaller, 93 gossipMempool, 94 validators, 95 txGossipClient, 96 txGossipMetrics, 97 gossip.BranchingFactor{ 98 StakePercentage: config.PushGossipPercentStake, 99 Validators: config.PushGossipNumValidators, 100 Peers: config.PushGossipNumPeers, 101 }, 102 gossip.BranchingFactor{ 103 Validators: config.PushRegossipNumValidators, 104 Peers: config.PushRegossipNumPeers, 105 }, 106 config.PushGossipDiscardedCacheSize, 107 config.TargetGossipSize, 108 config.PushGossipMaxRegossipFrequency, 109 ) 110 if err != nil { 111 return nil, err 112 } 113 114 var txPullGossiper gossip.Gossiper = gossip.NewPullGossiper[*txs.Tx]( 115 log, 116 marshaller, 117 gossipMempool, 118 txGossipClient, 119 txGossipMetrics, 120 config.PullGossipPollSize, 121 ) 122 123 // Gossip requests are only served if a node is a validator 124 txPullGossiper = gossip.ValidatorGossiper{ 125 Gossiper: txPullGossiper, 126 NodeID: nodeID, 127 Validators: validators, 128 } 129 130 handler := gossip.NewHandler[*txs.Tx]( 131 log, 132 marshaller, 133 gossipMempool, 134 txGossipMetrics, 135 config.TargetGossipSize, 136 ) 137 138 validatorHandler := p2p.NewValidatorHandler( 139 p2p.NewThrottlerHandler( 140 handler, 141 p2p.NewSlidingWindowThrottler( 142 config.PullGossipThrottlingPeriod, 143 config.PullGossipThrottlingLimit, 144 ), 145 log, 146 ), 147 validators, 148 log, 149 ) 150 151 // We allow pushing txs between all peers, but only serve gossip requests 152 // from validators 153 txGossipHandler := txGossipHandler{ 154 appGossipHandler: handler, 155 appRequestHandler: validatorHandler, 156 } 157 158 if err := p2pNetwork.AddHandler(p2p.TxGossipHandlerID, txGossipHandler); err != nil { 159 return nil, err 160 } 161 162 return &Network{ 163 Network: p2pNetwork, 164 log: log, 165 parser: parser, 166 mempool: gossipMempool, 167 appSender: appSender, 168 txPushGossiper: txPushGossiper, 169 txPushGossipFrequency: config.PushGossipFrequency, 170 txPullGossiper: txPullGossiper, 171 txPullGossipFrequency: config.PullGossipFrequency, 172 }, nil 173 } 174 175 func (n *Network) PushGossip(ctx context.Context) { 176 gossip.Every(ctx, n.log, n.txPushGossiper, n.txPushGossipFrequency) 177 } 178 179 func (n *Network) PullGossip(ctx context.Context) { 180 gossip.Every(ctx, n.log, n.txPullGossiper, n.txPullGossipFrequency) 181 } 182 183 // IssueTxFromRPC attempts to add a tx to the mempool, after verifying it. If 184 // the tx is added to the mempool, it will attempt to push gossip the tx to 185 // random peers in the network. 186 // 187 // If the tx is already in the mempool, mempool.ErrDuplicateTx will be 188 // returned. 189 // If the tx is not added to the mempool, an error will be returned. 190 func (n *Network) IssueTxFromRPC(tx *txs.Tx) error { 191 if err := n.mempool.Add(tx); err != nil { 192 return err 193 } 194 n.txPushGossiper.Add(tx) 195 return nil 196 } 197 198 // IssueTxFromRPCWithoutVerification attempts to add a tx to the mempool, 199 // without first verifying it. If the tx is added to the mempool, it will 200 // attempt to push gossip the tx to random peers in the network. 201 // 202 // If the tx is already in the mempool, mempool.ErrDuplicateTx will be 203 // returned. 204 // If the tx is not added to the mempool, an error will be returned. 205 func (n *Network) IssueTxFromRPCWithoutVerification(tx *txs.Tx) error { 206 if err := n.mempool.AddWithoutVerification(tx); err != nil { 207 return err 208 } 209 n.txPushGossiper.Add(tx) 210 return nil 211 }