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 }