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