Files
zeekayandHanzo Dev b1cc108c9f gofmt
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 01:51:51 -07:00

229 lines
5.6 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package network
import (
"github.com/luxfi/metric"
"context"
"time"
"github.com/luxfi/ids"
"github.com/luxfi/log"
"github.com/luxfi/node/vms/txs/mempool"
"github.com/luxfi/node/vms/xvm/txs"
"github.com/luxfi/p2p"
"github.com/luxfi/p2p/gossip"
consensusvalidator "github.com/luxfi/validators"
"github.com/luxfi/warp"
)
var (
_ warp.Handler = (*Network)(nil)
_ consensusvalidator.Connector = (*Network)(nil)
)
type Network struct {
*p2p.Network
log log.Logger
mempool *gossipMempool
txPushGossiper *gossip.PushGossiper[*txs.Tx]
txPushGossipFrequency time.Duration
txPullGossiper gossip.Gossiper
txPullGossipFrequency time.Duration
}
func New(
log log.Logger,
nodeID ids.NodeID,
netID ids.ID,
vdrs consensusvalidator.State,
parser txs.Parser,
txVerifier TxVerifier,
mempool mempool.Mempool[*txs.Tx],
sender warp.Sender,
registerer metric.Registerer,
config Config,
) (*Network, error) {
p2pNetwork, err := p2p.NewNetwork(log, sender, registerer, "p2p")
if err != nil {
return nil, err
}
marshaller := &txParser{
parser: parser,
}
validators := p2p.NewValidators(
p2pNetwork.Peers,
log,
netID,
vdrs,
config.MaxValidatorSetStaleness,
)
txGossipClient := p2pNetwork.NewClient(
p2p.TxGossipHandlerID,
p2p.WithValidatorSampling(validators),
)
txGossipMetrics, err := gossip.NewMetrics(registerer, "tx")
if err != nil {
return nil, err
}
gossipMempool, err := newGossipMempool(
mempool,
registerer,
log,
txVerifier,
config.ExpectedBloomFilterElements,
config.ExpectedBloomFilterFalsePositiveProbability,
config.MaxBloomFilterFalsePositiveProbability,
)
if err != nil {
return nil, err
}
txPushGossiper, err := gossip.NewPushGossiper[*txs.Tx](
marshaller,
gossipMempool,
validators,
txGossipClient,
txGossipMetrics,
gossip.BranchingFactor{
StakePercentage: config.PushGossipPercentStake,
Validators: config.PushGossipNumValidators,
Peers: config.PushGossipNumPeers,
},
gossip.BranchingFactor{
Validators: config.PushRegossipNumValidators,
Peers: config.PushRegossipNumPeers,
},
config.PushGossipDiscardedCacheSize,
config.TargetGossipSize,
config.PushGossipMaxRegossipFrequency,
)
if err != nil {
return nil, err
}
var txPullGossiper gossip.Gossiper = gossip.NewPullGossiper[*txs.Tx](
log,
marshaller,
gossipMempool,
txGossipClient,
txGossipMetrics,
config.PullGossipPollSize,
)
// Gossip requests are only served if a node is a validator
txPullGossiper = gossip.ValidatorGossiper{
Gossiper: txPullGossiper,
NodeID: nodeID,
Validators: validators,
}
handler := gossip.NewHandler[*txs.Tx](
log,
marshaller,
gossipMempool,
txGossipMetrics,
config.TargetGossipSize,
nil, // BloomChecker - optional
)
validatorHandler := p2p.NewValidatorHandler(
p2p.NewThrottlerHandler(
handler,
p2p.NewSlidingWindowThrottler(
config.PullGossipThrottlingPeriod,
config.PullGossipThrottlingLimit,
),
log,
),
validators,
log,
)
// We allow pushing txs between all peers, but only serve gossip requests
// from validators
txGossipHandler := txGossipHandler{
gossipHandler: handler,
requestHandler: validatorHandler,
}
if err := p2pNetwork.AddHandler(p2p.TxGossipHandlerID, txGossipHandler); err != nil {
return nil, err
}
return &Network{
Network: p2pNetwork,
log: log,
mempool: gossipMempool,
txPushGossiper: txPushGossiper,
txPushGossipFrequency: config.PushGossipFrequency,
txPullGossiper: txPullGossiper,
txPullGossipFrequency: config.PullGossipFrequency,
}, nil
}
func (n *Network) PushGossip(ctx context.Context) {
gossip.Every(ctx, n.log, n.txPushGossiper, n.txPushGossipFrequency)
}
func (n *Network) PullGossip(ctx context.Context) {
gossip.Every(ctx, n.log, n.txPullGossiper, n.txPullGossipFrequency)
}
// IssueTxFromRPC attempts to add a tx to the mempool, after verifying it. If
// the tx is added to the mempool, it will attempt to push gossip the tx to
// random peers in the network.
//
// If the tx is already in the mempool, mempool.ErrDuplicateTx will be
// returned.
// If the tx is not added to the mempool, an error will be returned.
func (n *Network) IssueTxFromRPC(tx *txs.Tx) error {
if err := n.mempool.Add(tx); err != nil {
return err
}
n.txPushGossiper.Add(tx)
return nil
}
// IssueTxFromRPCWithoutVerification attempts to add a tx to the mempool,
// without first verifying it. If the tx is added to the mempool, it will
// attempt to push gossip the tx to random peers in the network.
//
// If the tx is already in the mempool, mempool.ErrDuplicateTx will be
// returned.
// If the tx is not added to the mempool, an error will be returned.
func (n *Network) IssueTxFromRPCWithoutVerification(tx *txs.Tx) error {
if err := n.mempool.AddWithoutVerification(tx); err != nil {
return err
}
n.txPushGossiper.Add(tx)
return nil
}
// Gossip handles gossip messages
func (n *Network) Gossip(ctx context.Context, nodeID ids.NodeID, msg []byte) error {
// Handle gossip message
return nil
}
// Request handles requests
func (n *Network) Request(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, msg []byte) ([]byte, *p2p.Error) {
return nil, nil
}
// RequestFailed handles failed requests
func (n *Network) RequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32, err *p2p.Error) error {
return nil
}
// Response handles responses
func (n *Network) Response(ctx context.Context, nodeID ids.NodeID, requestID uint32, msg []byte) error {
return nil
}