github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/network/gossip.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  	"fmt"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/prometheus/client_golang/prometheus"
    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/utils/logging"
    19  	"github.com/ava-labs/avalanchego/vms/platformvm/txs"
    20  	"github.com/ava-labs/avalanchego/vms/txs/mempool"
    21  
    22  	pmempool "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool"
    23  )
    24  
    25  var (
    26  	_ p2p.Handler                = (*txGossipHandler)(nil)
    27  	_ gossip.Marshaller[*txs.Tx] = (*txMarshaller)(nil)
    28  	_ gossip.Gossipable          = (*txs.Tx)(nil)
    29  )
    30  
    31  // bloomChurnMultiplier is the number used to multiply the size of the mempool
    32  // to determine how large of a bloom filter to create.
    33  const bloomChurnMultiplier = 3
    34  
    35  // txGossipHandler is the handler called when serving gossip messages
    36  type txGossipHandler struct {
    37  	p2p.NoOpHandler
    38  	appGossipHandler  p2p.Handler
    39  	appRequestHandler p2p.Handler
    40  }
    41  
    42  func (t txGossipHandler) AppGossip(
    43  	ctx context.Context,
    44  	nodeID ids.NodeID,
    45  	gossipBytes []byte,
    46  ) {
    47  	t.appGossipHandler.AppGossip(ctx, nodeID, gossipBytes)
    48  }
    49  
    50  func (t txGossipHandler) AppRequest(
    51  	ctx context.Context,
    52  	nodeID ids.NodeID,
    53  	deadline time.Time,
    54  	requestBytes []byte,
    55  ) ([]byte, *common.AppError) {
    56  	return t.appRequestHandler.AppRequest(ctx, nodeID, deadline, requestBytes)
    57  }
    58  
    59  type txMarshaller struct{}
    60  
    61  func (txMarshaller) MarshalGossip(tx *txs.Tx) ([]byte, error) {
    62  	return tx.Bytes(), nil
    63  }
    64  
    65  func (txMarshaller) UnmarshalGossip(bytes []byte) (*txs.Tx, error) {
    66  	return txs.Parse(txs.Codec, bytes)
    67  }
    68  
    69  func newGossipMempool(
    70  	mempool pmempool.Mempool,
    71  	registerer prometheus.Registerer,
    72  	log logging.Logger,
    73  	txVerifier TxVerifier,
    74  	minTargetElements int,
    75  	targetFalsePositiveProbability,
    76  	resetFalsePositiveProbability float64,
    77  ) (*gossipMempool, error) {
    78  	bloom, err := gossip.NewBloomFilter(registerer, "mempool_bloom_filter", minTargetElements, targetFalsePositiveProbability, resetFalsePositiveProbability)
    79  	return &gossipMempool{
    80  		Mempool:    mempool,
    81  		log:        log,
    82  		txVerifier: txVerifier,
    83  		bloom:      bloom,
    84  	}, err
    85  }
    86  
    87  type gossipMempool struct {
    88  	pmempool.Mempool
    89  	log        logging.Logger
    90  	txVerifier TxVerifier
    91  
    92  	lock  sync.RWMutex
    93  	bloom *gossip.BloomFilter
    94  }
    95  
    96  func (g *gossipMempool) Add(tx *txs.Tx) error {
    97  	txID := tx.ID()
    98  	if _, ok := g.Mempool.Get(txID); ok {
    99  		return fmt.Errorf("tx %s dropped: %w", txID, mempool.ErrDuplicateTx)
   100  	}
   101  
   102  	if reason := g.Mempool.GetDropReason(txID); reason != nil {
   103  		// If the tx is being dropped - just ignore it
   104  		//
   105  		// TODO: Should we allow re-verification of the transaction even if it
   106  		// failed previously?
   107  		return reason
   108  	}
   109  
   110  	if err := g.txVerifier.VerifyTx(tx); err != nil {
   111  		g.Mempool.MarkDropped(txID, err)
   112  		return err
   113  	}
   114  
   115  	if err := g.Mempool.Add(tx); err != nil {
   116  		g.Mempool.MarkDropped(txID, err)
   117  		return err
   118  	}
   119  
   120  	g.lock.Lock()
   121  	defer g.lock.Unlock()
   122  
   123  	g.bloom.Add(tx)
   124  	reset, err := gossip.ResetBloomFilterIfNeeded(g.bloom, g.Mempool.Len()*bloomChurnMultiplier)
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	if reset {
   130  		g.log.Debug("resetting bloom filter")
   131  		g.Mempool.Iterate(func(tx *txs.Tx) bool {
   132  			g.bloom.Add(tx)
   133  			return true
   134  		})
   135  	}
   136  
   137  	g.Mempool.RequestBuildBlock(false)
   138  	return nil
   139  }
   140  
   141  func (g *gossipMempool) Has(txID ids.ID) bool {
   142  	_, ok := g.Mempool.Get(txID)
   143  	return ok
   144  }
   145  
   146  func (g *gossipMempool) GetFilter() (bloom []byte, salt []byte) {
   147  	g.lock.RLock()
   148  	defer g.lock.RUnlock()
   149  
   150  	return g.bloom.Marshal()
   151  }