mirror of
https://github.com/luxfi/proto.git
synced 2026-10-30 15:21:09 +00:00
Adds .hanzo/workflows/cicd.yml calling the canonical pipeline and drops the GitHub-hosted workflows it replaces. Lands here because this is where the repo is written — git.hanzo.ai is upstream and github.com is its push mirror, so the same change made on github.com never reaches the runner fleet.
156 lines
3.5 KiB
Go
156 lines
3.5 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package network
|
|
|
|
import (
|
|
"go.uber.org/zap"
|
|
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/luxfi/log"
|
|
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/metric"
|
|
"github.com/luxfi/p2p"
|
|
"github.com/luxfi/p2p/gossip"
|
|
"github.com/luxfi/proto/p/txs"
|
|
"github.com/luxfi/proto/txs/mempool"
|
|
"github.com/luxfi/warp"
|
|
)
|
|
|
|
var (
|
|
_ p2p.Handler = (*txGossipHandler)(nil)
|
|
_ gossip.Marshaller[*txs.Tx] = (*txMarshaller)(nil)
|
|
_ gossip.Gossipable = (*txs.Tx)(nil)
|
|
)
|
|
|
|
// bloomChurnMultiplier is the number used to multiply the size of the mempool
|
|
// to determine how large of a bloom filter to create.
|
|
const bloomChurnMultiplier = 3
|
|
|
|
// txGossipHandler is the handler called when serving gossip messages
|
|
type txGossipHandler struct {
|
|
p2p.NoOpHandler
|
|
appGossipHandler p2p.Handler
|
|
appRequestHandler p2p.Handler
|
|
}
|
|
|
|
func (t txGossipHandler) Gossip(
|
|
ctx context.Context,
|
|
nodeID ids.NodeID,
|
|
gossipBytes []byte,
|
|
) {
|
|
t.appGossipHandler.Gossip(ctx, nodeID, gossipBytes)
|
|
}
|
|
|
|
func (t txGossipHandler) Request(
|
|
ctx context.Context,
|
|
nodeID ids.NodeID,
|
|
deadline time.Time,
|
|
requestBytes []byte,
|
|
) ([]byte, *warp.Error) {
|
|
return t.appRequestHandler.Request(ctx, nodeID, deadline, requestBytes)
|
|
}
|
|
|
|
// txMarshaller is the gossip [bytes]<->[*txs.Tx] encoder. A tx is
|
|
// self-describing on the wire, so it holds no state.
|
|
type txMarshaller struct{}
|
|
|
|
func (txMarshaller) MarshalGossip(tx *txs.Tx) ([]byte, error) {
|
|
return tx.Bytes(), nil
|
|
}
|
|
|
|
func (m txMarshaller) UnmarshalGossip(bytes []byte) (*txs.Tx, error) {
|
|
return txs.Parse(bytes)
|
|
}
|
|
|
|
func newGossipMempool(
|
|
mempool mempool.Mempool[*txs.Tx],
|
|
registerer metric.Registerer,
|
|
log log.Logger,
|
|
txVerifier TxVerifier,
|
|
minTargetElements int,
|
|
targetFalsePositiveProbability,
|
|
resetFalsePositiveProbability float64,
|
|
) (*gossipMempool, error) {
|
|
bloom, err := gossip.NewBloomFilter(registerer, "mempool_bloom_filter", minTargetElements, targetFalsePositiveProbability, resetFalsePositiveProbability)
|
|
return &gossipMempool{
|
|
Mempool: mempool,
|
|
log: log,
|
|
txVerifier: txVerifier,
|
|
bloom: bloom,
|
|
}, err
|
|
}
|
|
|
|
type gossipMempool struct {
|
|
mempool.Mempool[*txs.Tx]
|
|
log log.Logger
|
|
txVerifier TxVerifier
|
|
|
|
lock sync.RWMutex
|
|
bloom *gossip.BloomFilter
|
|
}
|
|
|
|
func (g *gossipMempool) Add(tx *txs.Tx) error {
|
|
txID := tx.ID()
|
|
if _, ok := g.Mempool.Get(txID); ok {
|
|
return fmt.Errorf("tx %s dropped: %w", txID, mempool.ErrDuplicateTx)
|
|
}
|
|
|
|
if reason := g.Mempool.GetDropReason(txID); reason != nil {
|
|
// If the tx is being dropped - just ignore it
|
|
//
|
|
// failed previously?
|
|
return reason
|
|
}
|
|
|
|
if err := g.txVerifier.VerifyTx(tx); err != nil {
|
|
g.log.Debug("transaction failed verification",
|
|
log.Stringer("txID", txID),
|
|
zap.Error(err),
|
|
)
|
|
|
|
g.Mempool.MarkDropped(txID, err)
|
|
return fmt.Errorf("failed verification: %w", err)
|
|
}
|
|
|
|
if err := g.Mempool.Add(tx); err != nil {
|
|
g.Mempool.MarkDropped(txID, err)
|
|
return err
|
|
}
|
|
|
|
g.lock.Lock()
|
|
defer g.lock.Unlock()
|
|
|
|
g.bloom.Add(tx)
|
|
reset, err := gossip.ResetBloomFilterIfNeeded(g.bloom, g.Mempool.Len()*bloomChurnMultiplier)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if reset {
|
|
g.log.Debug("resetting bloom filter")
|
|
g.Mempool.Iterate(func(tx *txs.Tx) bool {
|
|
g.bloom.Add(tx)
|
|
return true
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *gossipMempool) Has(txID ids.ID) bool {
|
|
_, ok := g.Mempool.Get(txID)
|
|
return ok
|
|
}
|
|
|
|
func (g *gossipMempool) GetFilter() (bloom []byte, salt []byte) {
|
|
g.lock.RLock()
|
|
defer g.lock.RUnlock()
|
|
|
|
return g.bloom.Marshal()
|
|
}
|