Expand P2 test coverage: mining chain, spread lanes, path forge, WS/beacon, E2E onion, file handling
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
This commit is contained in:
88
server/internal/atlas/lan_gossip.go
Normal file
88
server/internal/atlas/lan_gossip.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package atlas
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"crypto-miner-server/internal/strategy"
|
||||
)
|
||||
|
||||
// GossipHint is one negative-knowledge skip shared between LAN siblings.
|
||||
type GossipHint struct {
|
||||
Tier string `json:"tier"`
|
||||
Condition string `json:"condition"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// SubnetPrefix returns the /24 (IPv4) or /48-ish (IPv6) prefix used for LAN sibling matching.
|
||||
func SubnetPrefix(ip string) string {
|
||||
return strategy.FingerprintFromAuth("", ip, false).Subnet
|
||||
}
|
||||
|
||||
// NormalizeGossipHint trims and validates one gossip hint.
|
||||
func NormalizeGossipHint(h GossipHint) (GossipHint, bool) {
|
||||
h.Tier = strings.TrimSpace(h.Tier)
|
||||
h.Condition = strings.TrimSpace(h.Condition)
|
||||
h.Reason = strings.TrimSpace(h.Reason)
|
||||
if h.Tier == "" || h.Condition == "" {
|
||||
return GossipHint{}, false
|
||||
}
|
||||
if h.Reason == "" {
|
||||
h.Reason = "lan gossip"
|
||||
}
|
||||
return h, true
|
||||
}
|
||||
|
||||
// NormalizeGossipHints drops invalid hints while preserving order.
|
||||
func NormalizeGossipHints(in []GossipHint) []GossipHint {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]GossipHint, 0, len(in))
|
||||
for _, h := range in {
|
||||
if norm, ok := NormalizeGossipHint(h); ok {
|
||||
out = append(out, norm)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SkipsFromHints converts gossip hints to atlas skips for agent merge.
|
||||
func SkipsFromHints(hints []GossipHint) []AtlasSkip {
|
||||
out := make([]AtlasSkip, 0, len(hints))
|
||||
for _, h := range hints {
|
||||
if norm, ok := NormalizeGossipHint(h); ok {
|
||||
out = append(out, AtlasSkip{
|
||||
Tier: norm.Tier,
|
||||
Condition: norm.Condition,
|
||||
Reason: norm.Reason,
|
||||
})
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// MergeGossipSkips merges incoming LAN hints into existing skips without duplicates.
|
||||
func MergeGossipSkips(existing []AtlasSkip, incoming []GossipHint) []AtlasSkip {
|
||||
hints := NormalizeGossipHints(incoming)
|
||||
if len(hints) == 0 {
|
||||
return existing
|
||||
}
|
||||
have := make(map[string]bool, len(existing)+len(hints))
|
||||
out := append([]AtlasSkip(nil), existing...)
|
||||
for _, s := range existing {
|
||||
have[s.Tier+"|"+s.Condition] = true
|
||||
}
|
||||
for _, h := range hints {
|
||||
key := h.Tier + "|" + h.Condition
|
||||
if have[key] {
|
||||
continue
|
||||
}
|
||||
have[key] = true
|
||||
out = append(out, AtlasSkip{
|
||||
Tier: h.Tier,
|
||||
Condition: h.Condition,
|
||||
Reason: h.Reason,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user