Files
AetherForge/server/internal/atlas/lan_gossip.go
AetherForge 7b2d41cda8
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Expand P2 test coverage: mining chain, spread lanes, path forge, WS/beacon, E2E onion, file handling
2026-06-07 04:58:55 -07:00

89 lines
2.2 KiB
Go

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
}