mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
vms/platformvm/... build + vet PASS with pcodecs/txs.Codec gone from the VM. Executor semantics (standard_tx_executor): - registerOwnSet(): shared primitive — per-validator state.L1Validator with native owner blobs (txs.MarshalOwner/UnmarshalOwner, no codec), active-set capacity check, EndAccumulatedFee=balance+accruedFees, SetNetToL1Conversion manager-authority recording (byte-for-byte legacy tail). - ConvertNetworkTx: promote endomorphism (owner-authorized, folds old ConvertNetworkToL1Tx), gated by security.Mode.Manager. - CreateNetworkTx: base (AddNet/SetNetOwner) + sovereign path registers own set. - Deleted CreateSovereignL1Tx + ConvertNetworkToL1Tx. - txs.UnmarshalOwner added: canonical owner marshal/unmarshal pair, no codec. All ~13 txs.Visitor impls carry ConvertNetworkTx; gossip/block Parse(b) codec-free; wallet/network/primary off txs.Codec. KNOWN GAP (pending design decision, NOT silently green): CreateNetworkTx reads tx.Chains() only to derive managerChainID — it does NOT create the genesis chains (no AddChain). Atomic-spawn-with-chains vs decomplect-to-CreateChainTx is the open call. 17 codec-era _test.go parked as .bak for follow-up rewrite. Co-authored-by: Hanzo Dev <dev@hanzo.ai>
154 lines
3.4 KiB
Go
154 lines
3.4 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"
|
|
|
|
"github.com/luxfi/log"
|
|
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/metric"
|
|
"github.com/luxfi/node/vms/platformvm/txs"
|
|
"github.com/luxfi/node/vms/txs/mempool"
|
|
"github.com/luxfi/p2p"
|
|
"github.com/luxfi/p2p/gossip"
|
|
"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)
|
|
}
|
|
|
|
type txMarshaller struct{}
|
|
|
|
func (txMarshaller) MarshalGossip(tx *txs.Tx) ([]byte, error) {
|
|
return tx.Bytes(), nil
|
|
}
|
|
|
|
func (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()
|
|
}
|