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  }