diff --git a/cmd/frostfs-node/netmap.go b/cmd/frostfs-node/netmap.go index e7d3271b..7d4831bc 100644 --- a/cmd/frostfs-node/netmap.go +++ b/cmd/frostfs-node/netmap.go @@ -282,11 +282,62 @@ func initNetmapState(c *cfg) { c.handleLocalNodeInfo(ni) } -func sameNodeInfo(a, b *netmapSDK.NodeInfo) bool { - // Suboptimal, but we do this once on the node startup. - rawA := a.Marshal() - rawB := b.Marshal() - return bytes.Equal(rawA, rawB) +func needsUpdate(local, remote *netmapSDK.NodeInfo) bool { + return bytes.Equal(local.PublicKey(), remote.PublicKey()) && equalEndpoints(local, remote) && equalAttributes(local, remote) +} + +func equalAttributes(local, remote *netmapSDK.NodeInfo) bool { + asA := make(map[string]string) + local.IterateAttributes(func(k, v string) { + asA[k] = v + }) + + allMatched := true + count := 0 + remote.IterateAttributes(func(k, vb string) { + // IR adds new attributes derived from the locode, they should be skipped. + if isLocodeAttribute(k) { + return + } + if va, ok := asA[k]; !ok || va != vb { + allMatched = false + return + } + count++ + }) + return allMatched && count == len(asA) +} + +func isLocodeAttribute(k string) bool { + // See https://git.frostfs.info/TrueCloudLab/frostfs-api/src/branch/master/netmap/types.proto#L171 + switch k { + case "Continent", "Country", "CountryCode", "Location", "SubDiv", "SubDivCode": + return true + default: + return false + } +} + +func equalEndpoints(a, b *netmapSDK.NodeInfo) bool { + var esA, esB []string + a.IterateNetworkEndpoints(func(e string) bool { + esA = append(esA, e) + return false + }) + b.IterateNetworkEndpoints(func(e string) bool { + esB = append(esB, e) + return false + }) + + if len(esA) != len(esB) { + return false + } + for i := range esA { + if esA[i] != esB[i] { + return false + } + } + return true } func nodeState(ni *netmapSDK.NodeInfo) string { @@ -314,7 +365,7 @@ func (c *cfg) netmapInitLocalNodeState(epoch uint64) (*netmapSDK.NodeInfo, bool, for i := range nmNodes { if bytes.Equal(nmNodes[i].PublicKey(), c.binPublicKey) { candidate = &nmNodes[i] - alreadyBootstraped = candidate.IsOnline() && sameNodeInfo(&c.cfgNodeInfo.localInfo, candidate) + alreadyBootstraped = candidate.IsOnline() && needsUpdate(&c.cfgNodeInfo.localInfo, candidate) break } }