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  }