github.com/braveheart12/insolar-09-08-19@v0.8.7/network/nodenetwork/nodekeeper.go (about) 1 /* 2 * The Clear BSD License 3 * 4 * Copyright (c) 2019 Insolar Technologies 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: 9 * 10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 * Neither the name of Insolar Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 * 14 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 * 16 */ 17 18 package nodenetwork 19 20 import ( 21 "context" 22 "net" 23 "sort" 24 "strings" 25 "sync" 26 27 "github.com/insolar/insolar/instrumentation/inslogger" 28 29 "github.com/insolar/insolar/configuration" 30 "github.com/insolar/insolar/consensus" 31 consensusPackets "github.com/insolar/insolar/consensus/packets" 32 "github.com/insolar/insolar/core" 33 "github.com/insolar/insolar/log" 34 "github.com/insolar/insolar/network" 35 "github.com/insolar/insolar/network/transport" 36 "github.com/insolar/insolar/network/transport/host" 37 "github.com/insolar/insolar/network/utils" 38 "github.com/insolar/insolar/version" 39 "github.com/pkg/errors" 40 "go.opencensus.io/stats" 41 ) 42 43 // NewNodeNetwork create active node component 44 func NewNodeNetwork(configuration configuration.HostNetwork, certificate core.Certificate) (core.NodeNetwork, error) { 45 origin, err := createOrigin(configuration, certificate) 46 if err != nil { 47 return nil, errors.Wrap(err, "Failed to create origin node") 48 } 49 nodeKeeper := NewNodeKeeper(origin) 50 nodeKeeper.SetState(core.WaitingNodeNetworkState) 51 if len(certificate.GetDiscoveryNodes()) == 0 || utils.OriginIsDiscovery(certificate) { 52 nodeKeeper.SetState(core.ReadyNodeNetworkState) 53 nodeKeeper.AddActiveNodes([]core.Node{origin}) 54 } 55 return nodeKeeper, nil 56 } 57 58 func createOrigin(configuration configuration.HostNetwork, certificate core.Certificate) (MutableNode, error) { 59 publicAddress, err := resolveAddress(configuration) 60 if err != nil { 61 return nil, errors.Wrap(err, "Failed to resolve public address") 62 } 63 64 role := certificate.GetRole() 65 if role == core.StaticRoleUnknown { 66 log.Info("[ createOrigin ] Use core.StaticRoleLightMaterial, since no role in certificate") 67 role = core.StaticRoleLightMaterial 68 } 69 70 return newMutableNode( 71 *certificate.GetNodeRef(), 72 role, 73 certificate.GetPublicKey(), 74 publicAddress, 75 version.Version, 76 ), nil 77 } 78 79 func resolveAddress(configuration configuration.HostNetwork) (string, error) { 80 addr, err := net.ResolveTCPAddr("tcp", configuration.Transport.Address) 81 if err != nil { 82 return "", err 83 } 84 address, err := transport.Resolve(configuration.Transport, addr.String()) 85 if err != nil { 86 return "", err 87 } 88 return address, nil 89 } 90 91 // NewNodeKeeper create new NodeKeeper 92 func NewNodeKeeper(origin core.Node) network.NodeKeeper { 93 return &nodekeeper{ 94 origin: origin, 95 state: core.ReadyNodeNetworkState, 96 claimQueue: newClaimQueue(), 97 active: make(map[core.RecordRef]core.Node), 98 indexNode: make(map[core.StaticRole]*recordRefSet), 99 indexShortID: make(map[core.ShortNodeID]core.Node), 100 tempMapR: make(map[core.RecordRef]*host.Host), 101 tempMapS: make(map[core.ShortNodeID]*host.Host), 102 sync: newUnsyncList(origin, []core.Node{}, 0), 103 } 104 } 105 106 type nodekeeper struct { 107 origin core.Node 108 claimQueue *claimQueue 109 110 nodesJoinedDuringPrevPulse bool 111 112 cloudHashLock sync.RWMutex 113 cloudHash []byte 114 115 activeLock sync.RWMutex 116 active map[core.RecordRef]core.Node 117 indexNode map[core.StaticRole]*recordRefSet 118 indexShortID map[core.ShortNodeID]core.Node 119 120 tempLock sync.RWMutex 121 tempMapR map[core.RecordRef]*host.Host 122 tempMapS map[core.ShortNodeID]*host.Host 123 124 syncLock sync.Mutex 125 sync network.UnsyncList 126 state core.NodeNetworkState 127 128 isBootstrap bool 129 isBootstrapLock sync.RWMutex 130 131 Cryptography core.CryptographyService `inject:""` 132 Handler core.TerminationHandler `inject:""` 133 } 134 135 func (nk *nodekeeper) GetWorkingNode(ref core.RecordRef) core.Node { 136 node := nk.GetActiveNode(ref) 137 138 if node == nil || node.Leaving() || !node.IsWorking() { 139 return nil 140 } 141 142 return node 143 } 144 145 func (nk *nodekeeper) GetWorkingNodesByRole(role core.DynamicRole) []core.RecordRef { 146 nk.activeLock.RLock() 147 defer nk.activeLock.RUnlock() 148 149 list, exists := nk.indexNode[jetRoleToNodeRole(role)] 150 if !exists { 151 return nil 152 } 153 return list.Collect() 154 } 155 156 func (nk *nodekeeper) Wipe(isDiscovery bool) { 157 log.Warn("don't use it in production") 158 159 nk.isBootstrapLock.Lock() 160 nk.isBootstrap = false 161 nk.isBootstrapLock.Unlock() 162 163 nk.tempLock.Lock() 164 nk.tempMapR = make(map[core.RecordRef]*host.Host) 165 nk.tempMapS = make(map[core.ShortNodeID]*host.Host) 166 nk.tempLock.Unlock() 167 168 nk.cloudHashLock.Lock() 169 nk.cloudHash = nil 170 nk.cloudHashLock.Unlock() 171 172 nk.activeLock.Lock() 173 defer nk.activeLock.Unlock() 174 175 nk.claimQueue = newClaimQueue() 176 nk.nodesJoinedDuringPrevPulse = false 177 nk.active = make(map[core.RecordRef]core.Node) 178 nk.reindex() 179 nk.syncLock.Lock() 180 nk.sync = newUnsyncList(nk.origin, []core.Node{}, 0) 181 if isDiscovery { 182 nk.addActiveNode(nk.origin) 183 nk.state = core.ReadyNodeNetworkState 184 } 185 nk.syncLock.Unlock() 186 } 187 188 func (nk *nodekeeper) AddTemporaryMapping(nodeID core.RecordRef, shortID core.ShortNodeID, address string) error { 189 consensusAddress, err := incrementPort(address) 190 if err != nil { 191 return errors.Wrapf(err, "Failed to increment port for address %s", address) 192 } 193 h, err := host.NewHostNS(consensusAddress, nodeID, shortID) 194 if err != nil { 195 return errors.Wrapf(err, "Failed to generate address (%s, %s, %d)", consensusAddress, nodeID, shortID) 196 } 197 nk.tempLock.Lock() 198 nk.tempMapR[nodeID] = h 199 nk.tempMapS[shortID] = h 200 nk.tempLock.Unlock() 201 log.Infof("Added temporary mapping: %s -> (%s, %d)", consensusAddress, nodeID, shortID) 202 return nil 203 } 204 205 func (nk *nodekeeper) ResolveConsensus(shortID core.ShortNodeID) *host.Host { 206 nk.tempLock.RLock() 207 defer nk.tempLock.RUnlock() 208 209 return nk.tempMapS[shortID] 210 } 211 212 func (nk *nodekeeper) ResolveConsensusRef(nodeID core.RecordRef) *host.Host { 213 nk.tempLock.RLock() 214 defer nk.tempLock.RUnlock() 215 216 return nk.tempMapR[nodeID] 217 } 218 219 // TODO: remove this method when bootstrap mechanism completed 220 // IsBootstrapped method returns true when bootstrapNodes are connected to each other 221 func (nk *nodekeeper) IsBootstrapped() bool { 222 nk.isBootstrapLock.RLock() 223 defer nk.isBootstrapLock.RUnlock() 224 225 return nk.isBootstrap 226 } 227 228 // TODO: remove this method when bootstrap mechanism completed 229 // SetIsBootstrapped method set is bootstrap completed 230 func (nk *nodekeeper) SetIsBootstrapped(isBootstrap bool) { 231 nk.isBootstrapLock.Lock() 232 defer nk.isBootstrapLock.Unlock() 233 234 nk.isBootstrap = isBootstrap 235 } 236 237 func (nk *nodekeeper) GetOrigin() core.Node { 238 nk.activeLock.RLock() 239 defer nk.activeLock.RUnlock() 240 241 return nk.origin 242 } 243 244 func (nk *nodekeeper) GetCloudHash() []byte { 245 nk.cloudHashLock.RLock() 246 defer nk.cloudHashLock.RUnlock() 247 248 return nk.cloudHash 249 } 250 251 func (nk *nodekeeper) SetCloudHash(cloudHash []byte) { 252 nk.cloudHashLock.Lock() 253 defer nk.cloudHashLock.Unlock() 254 255 nk.cloudHash = cloudHash 256 } 257 258 func (nk *nodekeeper) GetActiveNodes() []core.Node { 259 nk.activeLock.RLock() 260 result := make([]core.Node, len(nk.active)) 261 index := 0 262 for _, node := range nk.active { 263 result[index] = node 264 index++ 265 } 266 nk.activeLock.RUnlock() 267 // Sort active nodes to return list with determinate order on every node. 268 // If we have more than 10k nodes, we need to optimize this 269 sort.Slice(result, func(i, j int) bool { 270 return result[i].ID().Compare(result[j].ID()) < 0 271 }) 272 return result 273 } 274 275 func (nk *nodekeeper) AddActiveNodes(nodes []core.Node) { 276 nk.activeLock.Lock() 277 defer nk.activeLock.Unlock() 278 279 activeNodes := make([]string, len(nodes)) 280 for i, node := range nodes { 281 nk.addActiveNode(node) 282 activeNodes[i] = node.ID().String() 283 } 284 syncList := nk.sync.(*unsyncList) 285 syncList.addNodes(nodes) 286 log.Debugf("Added active nodes: %s", strings.Join(activeNodes, ", ")) 287 } 288 289 func (nk *nodekeeper) GetActiveNode(ref core.RecordRef) core.Node { 290 nk.activeLock.RLock() 291 defer nk.activeLock.RUnlock() 292 293 return nk.active[ref] 294 } 295 296 func (nk *nodekeeper) GetActiveNodeByShortID(shortID core.ShortNodeID) core.Node { 297 nk.activeLock.RLock() 298 defer nk.activeLock.RUnlock() 299 300 return nk.indexShortID[shortID] 301 } 302 303 func (nk *nodekeeper) addActiveNode(node core.Node) { 304 if node.ID().Equal(nk.origin.ID()) { 305 nk.origin = node 306 log.Infof("Added origin node %s to active list", nk.origin.ID()) 307 } 308 nk.active[node.ID()] = node 309 310 nk.addToIndex(node) 311 } 312 313 func (nk *nodekeeper) addToIndex(node core.Node) { 314 nk.indexShortID[node.ShortID()] = node 315 nk.addToRoleIndex(node) 316 } 317 318 func (nk *nodekeeper) addToRoleIndex(node core.Node) { 319 if node.Leaving() || !node.IsWorking() { 320 return 321 } 322 323 list, ok := nk.indexNode[node.Role()] 324 if !ok { 325 list = newRecordRefSet() 326 } 327 328 list.Add(node.ID()) 329 nk.indexNode[node.Role()] = list 330 } 331 332 func (nk *nodekeeper) GetWorkingNodes() []core.Node { 333 var workingNodes []core.Node 334 activeNodes := nk.GetActiveNodes() 335 for _, node := range activeNodes { 336 if !node.Leaving() && node.IsWorking() { 337 workingNodes = append(workingNodes, node) 338 } 339 } 340 341 return workingNodes 342 } 343 344 func (nk *nodekeeper) SetState(state core.NodeNetworkState) { 345 nk.syncLock.Lock() 346 defer nk.syncLock.Unlock() 347 348 nk.state = state 349 } 350 351 func (nk *nodekeeper) GetState() core.NodeNetworkState { 352 nk.syncLock.Lock() 353 defer nk.syncLock.Unlock() 354 355 return nk.state 356 } 357 358 func (nk *nodekeeper) GetOriginJoinClaim() (*consensusPackets.NodeJoinClaim, error) { 359 nk.activeLock.RLock() 360 defer nk.activeLock.RUnlock() 361 362 return nk.nodeToSignedClaim() 363 } 364 365 func (nk *nodekeeper) GetOriginAnnounceClaim(mapper consensusPackets.BitSetMapper) (*consensusPackets.NodeAnnounceClaim, error) { 366 nk.activeLock.RLock() 367 defer nk.activeLock.RUnlock() 368 369 return nk.nodeToAnnounceClaim(mapper) 370 } 371 372 func (nk *nodekeeper) AddPendingClaim(claim consensusPackets.ReferendumClaim) bool { 373 nk.claimQueue.Push(claim) 374 return true 375 } 376 377 func (nk *nodekeeper) GetClaimQueue() network.ClaimQueue { 378 return nk.claimQueue 379 } 380 381 func (nk *nodekeeper) NodesJoinedDuringPreviousPulse() bool { 382 nk.activeLock.RLock() 383 defer nk.activeLock.RUnlock() 384 385 return nk.nodesJoinedDuringPrevPulse 386 } 387 388 func (nk *nodekeeper) GetUnsyncList() network.UnsyncList { 389 activeNodes := nk.GetActiveNodes() 390 return newUnsyncList(nk.origin, activeNodes, len(activeNodes)) 391 } 392 393 func (nk *nodekeeper) GetSparseUnsyncList(length int) network.UnsyncList { 394 return newSparseUnsyncList(nk.origin, length) 395 } 396 397 func (nk *nodekeeper) Sync(list network.UnsyncList) { 398 nk.syncLock.Lock() 399 defer nk.syncLock.Unlock() 400 401 nodes := list.GetActiveNodes() 402 403 foundOrigin := false 404 for _, node := range nodes { 405 if node.ID().Equal(nk.origin.ID()) { 406 foundOrigin = true 407 nk.state = core.ReadyNodeNetworkState 408 } 409 } 410 411 if nk.shouldExit(foundOrigin) { 412 nk.gracefullyStop() 413 } 414 415 nk.sync = list 416 } 417 418 func (nk *nodekeeper) MoveSyncToActive(ctx context.Context) error { 419 nk.activeLock.Lock() 420 nk.syncLock.Lock() 421 defer func() { 422 nk.syncLock.Unlock() 423 nk.activeLock.Unlock() 424 }() 425 426 nk.tempLock.Lock() 427 // clear temporary mappings 428 nk.tempMapR = make(map[core.RecordRef]*host.Host) 429 nk.tempMapS = make(map[core.ShortNodeID]*host.Host) 430 nk.tempLock.Unlock() 431 432 mergeResult, err := nk.sync.GetMergedCopy() 433 if err != nil { 434 return errors.Wrap(err, "[ MoveSyncToActive ] Failed to calculate new active list") 435 } 436 437 inslogger.FromContext(ctx).Infof("[ MoveSyncToActive ] New active list confirmed. Active list size: %d -> %d", 438 len(nk.active), len(mergeResult.ActiveList)) 439 nk.active = mergeResult.ActiveList 440 stats.Record(ctx, consensus.ActiveNodes.M(int64(len(nk.active)))) 441 nk.reindex() 442 nk.nodesJoinedDuringPrevPulse = mergeResult.NodesJoinedDuringPrevPulse 443 return nil 444 } 445 446 func (nk *nodekeeper) gracefullyStop() { 447 // TODO: graceful stop 448 nk.Handler.Abort("Node leave acknowledged by network. Goodbye!") 449 } 450 451 func (nk *nodekeeper) reindex() { 452 // drop all indexes 453 nk.indexNode = make(map[core.StaticRole]*recordRefSet) 454 nk.indexShortID = make(map[core.ShortNodeID]core.Node) 455 456 for _, node := range nk.active { 457 nk.addToIndex(node) 458 } 459 } 460 461 func (nk *nodekeeper) shouldExit(foundOrigin bool) bool { 462 return !foundOrigin && nk.state == core.ReadyNodeNetworkState && len(nk.active) != 0 463 } 464 465 func (nk *nodekeeper) nodeToSignedClaim() (*consensusPackets.NodeJoinClaim, error) { 466 claim, err := consensusPackets.NodeToClaim(nk.origin) 467 if err != nil { 468 return nil, err 469 } 470 dataToSign, err := claim.SerializeRaw() 471 log.Debugf("dataToSign len: %d", len(dataToSign)) 472 if err != nil { 473 return nil, errors.Wrap(err, "[ nodeToSignedClaim ] failed to serialize a claim") 474 } 475 sign, err := nk.sign(dataToSign) 476 log.Debugf("sign len: %d", len(sign)) 477 if err != nil { 478 return nil, errors.Wrap(err, "[ nodeToSignedClaim ] failed to sign a claim") 479 } 480 copy(claim.Signature[:], sign[:consensusPackets.SignatureLength]) 481 return claim, nil 482 } 483 484 func (nk *nodekeeper) nodeToAnnounceClaim(mapper consensusPackets.BitSetMapper) (*consensusPackets.NodeAnnounceClaim, error) { 485 claim := consensusPackets.NodeAnnounceClaim{} 486 joinClaim, err := consensusPackets.NodeToClaim(nk.origin) 487 if err != nil { 488 return nil, err 489 } 490 claim.NodeJoinClaim = *joinClaim 491 claim.NodeCount = uint16(mapper.Length()) 492 announcerIndex, err := mapper.RefToIndex(nk.origin.ID()) 493 if err != nil { 494 return nil, errors.Wrap(err, "[ nodeToAnnounceClaim ] failed to map origin node ID to bitset index") 495 } 496 claim.NodeAnnouncerIndex = uint16(announcerIndex) 497 claim.BitSetMapper = mapper 498 claim.SetCloudHash(nk.GetCloudHash()) 499 return &claim, nil 500 } 501 502 func (nk *nodekeeper) sign(data []byte) ([]byte, error) { 503 sign, err := nk.Cryptography.Sign(data) 504 if err != nil { 505 return nil, errors.Wrap(err, "[ sign ] failed to sign a claim") 506 } 507 return sign.Bytes(), nil 508 } 509 510 func jetRoleToNodeRole(role core.DynamicRole) core.StaticRole { 511 switch role { 512 case core.DynamicRoleVirtualExecutor: 513 return core.StaticRoleVirtual 514 case core.DynamicRoleVirtualValidator: 515 return core.StaticRoleVirtual 516 case core.DynamicRoleLightExecutor: 517 return core.StaticRoleLightMaterial 518 case core.DynamicRoleLightValidator: 519 return core.StaticRoleLightMaterial 520 case core.DynamicRoleHeavyExecutor: 521 return core.StaticRoleHeavyMaterial 522 default: 523 return core.StaticRoleUnknown 524 } 525 }