mirror of
https://github.com/luxfi/node.git
synced 2026-10-30 15:24:05 +00:00
229 lines
5.6 KiB
Go
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
|
|
}
|