Files
zeekayandHanzo Dev 920d56f2ec Carry the P and X chain packages the node still held
The platform and exchange VMs are the last chain code living in luxfi/node
and the reason the node cannot be retired. This brings over the part of them
proto did not already have: the adopt registry, the ZAP wire generators for
signer, warp and validator fees, the hybrid and runtime proof-of-possession
signers, the native admission check, the zwarp client and server, the
X-chain network layer, the xvmroot state root, the batch verifier and owner
root, and the credential policy the P and X mempools share, which lands
beside the mempool it gates as proto/txs/auth.

The X-chain genesis builder moves into proto/x/genesis, where the codec it
calls already lives, so it no longer reaches for the xvm package to build
primary-asset bytes.

Imports point at the packages that already have homes: cache, upgrade,
version and util as their own modules, and gas, verify and index in
luxfi/vm. The three generated files bring github.com/zap-proto/go with them,
which requires go 1.26.5.

Most of the remaining difference between the node's trees and proto is not a
backlog. proto restructured this code in August and the node's copies predate
it, so files that look absent are largely present here under other names.
What genuinely cannot come yet is anything reaching for node/server/http,
node/vms or node/wallet, and the tests written against tx constructors
proto's tx layer no longer exports.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-06 11:46:03 -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"
consensusvalidator "github.com/luxfi/validators"
"github.com/luxfi/ids"
"github.com/luxfi/log"
"github.com/luxfi/proto/x/txs"
"github.com/luxfi/proto/txs/mempool"
"github.com/luxfi/p2p"
"github.com/luxfi/p2p/gossip"
"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
}