github.com/braveheart12/just@v0.8.7/network/nodenetwork/unsync_list.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  	"sort"
    22  
    23  	consensus "github.com/insolar/insolar/consensus/packets"
    24  	"github.com/insolar/insolar/core"
    25  	"github.com/insolar/insolar/network"
    26  	"github.com/pkg/errors"
    27  )
    28  
    29  func copyActiveNodes(m map[core.RecordRef]core.Node) map[core.RecordRef]core.Node {
    30  	result := make(map[core.RecordRef]core.Node, len(m))
    31  	for k, v := range m {
    32  		v.(MutableNode).ChangeState()
    33  		result[k] = v
    34  	}
    35  	return result
    36  }
    37  
    38  type unsyncList struct {
    39  	length      int
    40  	origin      core.Node
    41  	activeNodes map[core.RecordRef]core.Node
    42  	claims      map[core.RecordRef][]consensus.ReferendumClaim
    43  	refToIndex  map[core.RecordRef]int
    44  	proofs      map[core.RecordRef]*consensus.NodePulseProof
    45  	ghs         map[core.RecordRef]consensus.GlobuleHashSignature
    46  	indexToRef  map[int]core.RecordRef
    47  	cache       []byte
    48  }
    49  
    50  func (ul *unsyncList) GetGlobuleHashSignature(ref core.RecordRef) (consensus.GlobuleHashSignature, bool) {
    51  	ghs, ok := ul.ghs[ref]
    52  	return ghs, ok
    53  }
    54  
    55  func (ul *unsyncList) SetGlobuleHashSignature(ref core.RecordRef, ghs consensus.GlobuleHashSignature) {
    56  	ul.ghs[ref] = ghs
    57  }
    58  
    59  func (ul *unsyncList) RemoveNode(nodeID core.RecordRef) {
    60  	delete(ul.activeNodes, nodeID)
    61  	delete(ul.claims, nodeID)
    62  	delete(ul.proofs, nodeID)
    63  	delete(ul.ghs, nodeID)
    64  }
    65  
    66  func (ul *unsyncList) ApproveSync(sync []core.RecordRef) {
    67  	prevActive := make([]core.RecordRef, 0, len(ul.activeNodes))
    68  	for nodeID := range ul.activeNodes {
    69  		prevActive = append(prevActive, nodeID)
    70  	}
    71  	diff := removeFromList(prevActive, sync)
    72  	for _, node := range diff {
    73  		ul.removeNode(node)
    74  	}
    75  }
    76  
    77  func (ul *unsyncList) AddNode(node core.Node, bitsetIndex uint16) {
    78  	ul.addNode(node, int(bitsetIndex))
    79  }
    80  
    81  func (ul *unsyncList) GetClaims(nodeID core.RecordRef) []consensus.ReferendumClaim {
    82  	return ul.claims[nodeID]
    83  }
    84  
    85  func (ul *unsyncList) AddProof(nodeID core.RecordRef, proof *consensus.NodePulseProof) {
    86  	ul.proofs[nodeID] = proof
    87  }
    88  
    89  func (ul *unsyncList) GetProof(nodeID core.RecordRef) *consensus.NodePulseProof {
    90  	return ul.proofs[nodeID]
    91  }
    92  
    93  func newUnsyncList(origin core.Node, activeNodesSorted []core.Node, length int) *unsyncList {
    94  	result := &unsyncList{
    95  		length:      length,
    96  		origin:      origin,
    97  		indexToRef:  make(map[int]core.RecordRef, len(activeNodesSorted)),
    98  		refToIndex:  make(map[core.RecordRef]int, len(activeNodesSorted)),
    99  		activeNodes: make(map[core.RecordRef]core.Node, len(activeNodesSorted)),
   100  	}
   101  	for i, node := range activeNodesSorted {
   102  		result.addNode(node, i)
   103  	}
   104  	result.proofs = make(map[core.RecordRef]*consensus.NodePulseProof)
   105  	result.claims = make(map[core.RecordRef][]consensus.ReferendumClaim)
   106  	result.ghs = make(map[core.RecordRef]consensus.GlobuleHashSignature)
   107  
   108  	return result
   109  }
   110  
   111  func (ul *unsyncList) addNodes(nodes []core.Node) {
   112  	sort.Slice(nodes, func(i, j int) bool {
   113  		return nodes[i].ID().Compare(nodes[j].ID()) < 0
   114  	})
   115  
   116  	for index, node := range nodes {
   117  		ul.addNode(node, index)
   118  	}
   119  }
   120  
   121  func (ul *unsyncList) addNode(node core.Node, index int) {
   122  	ul.indexToRef[index] = node.ID()
   123  	ul.refToIndex[node.ID()] = index
   124  	ul.activeNodes[node.ID()] = node
   125  }
   126  
   127  func (ul *unsyncList) removeNode(nodeID core.RecordRef) {
   128  	delete(ul.activeNodes, nodeID)
   129  	delete(ul.claims, nodeID)
   130  	delete(ul.proofs, nodeID)
   131  	delete(ul.ghs, nodeID)
   132  	i, ok := ul.refToIndex[nodeID]
   133  	if ok {
   134  		delete(ul.indexToRef, i)
   135  	}
   136  	delete(ul.refToIndex, nodeID)
   137  	ul.cache = nil
   138  }
   139  
   140  func (ul *unsyncList) AddClaims(claims map[core.RecordRef][]consensus.ReferendumClaim) error {
   141  	ul.claims = claims
   142  	ul.cache = nil
   143  	return nil
   144  }
   145  
   146  func (ul *unsyncList) CalculateHash(scheme core.PlatformCryptographyScheme) ([]byte, error) {
   147  	if ul.cache != nil {
   148  		return ul.cache, nil
   149  	}
   150  	m, err := ul.GetMergedCopy()
   151  	if err != nil {
   152  		return nil, errors.Wrap(err, "[ CalculateHash ] failed to merge a node map")
   153  	}
   154  	sorted := sortedNodeList(m.ActiveList)
   155  	ul.cache, err = CalculateHash(scheme, sorted)
   156  	return ul.cache, err
   157  }
   158  
   159  func (ul *unsyncList) GetActiveNode(ref core.RecordRef) core.Node {
   160  	return ul.activeNodes[ref]
   161  }
   162  
   163  func (ul *unsyncList) GetActiveNodes() []core.Node {
   164  	return sortedNodeList(ul.activeNodes)
   165  }
   166  
   167  func (ul *unsyncList) GetMergedCopy() (*network.MergedListCopy, error) {
   168  	nodes := copyActiveNodes(ul.activeNodes)
   169  
   170  	var nodesJoinedDuringPrevPulse bool
   171  	for _, claimList := range ul.claims {
   172  		for _, claim := range claimList {
   173  			isJoin, err := mergeClaim(nodes, claim)
   174  			if err != nil {
   175  				return nil, errors.Wrap(err, "[ GetMergedCopy ] failed to merge a claim")
   176  			}
   177  
   178  			nodesJoinedDuringPrevPulse = nodesJoinedDuringPrevPulse || isJoin
   179  		}
   180  	}
   181  
   182  	return &network.MergedListCopy{
   183  		ActiveList:                 nodes,
   184  		NodesJoinedDuringPrevPulse: nodesJoinedDuringPrevPulse,
   185  	}, nil
   186  }
   187  
   188  func mergeClaim(nodes map[core.RecordRef]core.Node, claim consensus.ReferendumClaim) (bool, error) {
   189  	isJoinClaim := false
   190  	switch t := claim.(type) {
   191  	case *consensus.NodeJoinClaim:
   192  		isJoinClaim = true
   193  		// TODO: fix version
   194  		node, err := ClaimToNode("", t)
   195  		if err != nil {
   196  			return isJoinClaim, errors.Wrap(err, "[ mergeClaim ] failed to convert Claim -> Node")
   197  		}
   198  		node.(MutableNode).SetState(core.NodeJoining)
   199  		nodes[node.ID()] = node
   200  	case *consensus.NodeLeaveClaim:
   201  		if nodes[t.NodeID] == nil {
   202  			break
   203  		}
   204  
   205  		node := nodes[t.NodeID].(MutableNode)
   206  		if t.ETA == 0 || !node.Leaving() {
   207  			node.SetLeavingETA(t.ETA)
   208  		}
   209  	}
   210  
   211  	return isJoinClaim, nil
   212  }
   213  
   214  func sortedNodeList(nodes map[core.RecordRef]core.Node) []core.Node {
   215  	result := make([]core.Node, len(nodes))
   216  	i := 0
   217  	for _, node := range nodes {
   218  		result[i] = node
   219  		i++
   220  	}
   221  	sort.Slice(result, func(i, j int) bool {
   222  		return result[i].ID().Compare(result[j].ID()) < 0
   223  	})
   224  	return result
   225  }
   226  
   227  func (ul *unsyncList) IndexToRef(index int) (core.RecordRef, error) {
   228  	if index < 0 || index >= ul.length {
   229  		return core.RecordRef{}, consensus.ErrBitSetOutOfRange
   230  	}
   231  	result, ok := ul.indexToRef[index]
   232  	if !ok {
   233  		return core.RecordRef{}, consensus.ErrBitSetNodeIsMissing
   234  	}
   235  	return result, nil
   236  }
   237  
   238  func (ul *unsyncList) RefToIndex(nodeID core.RecordRef) (int, error) {
   239  	index, ok := ul.refToIndex[nodeID]
   240  	if !ok {
   241  		return 0, consensus.ErrBitSetIncorrectNode
   242  	}
   243  	return index, nil
   244  }
   245  
   246  func (ul *unsyncList) Length() int {
   247  	return ul.length
   248  }
   249  
   250  type sparseUnsyncList struct {
   251  	unsyncList
   252  }
   253  
   254  func newSparseUnsyncList(origin core.Node, capacity int) *sparseUnsyncList {
   255  	return &sparseUnsyncList{unsyncList: *newUnsyncList(origin, nil, capacity)}
   256  }
   257  
   258  func (ul *sparseUnsyncList) AddClaims(claims map[core.RecordRef][]consensus.ReferendumClaim) error {
   259  	err := ul.unsyncList.AddClaims(claims)
   260  	if err != nil {
   261  		return errors.Wrap(err, "[ AddClaims ] failed to add a claims")
   262  	}
   263  
   264  	for _, claimList := range claims {
   265  		for _, claim := range claimList {
   266  			c, ok := claim.(*consensus.NodeAnnounceClaim)
   267  			if !ok {
   268  				continue
   269  			}
   270  
   271  			// TODO: fix version
   272  			node, err := ClaimToNode("", &c.NodeJoinClaim)
   273  			if err != nil {
   274  				return errors.Wrap(err, "[ AddClaims ] failed to convert Claim -> Node")
   275  			}
   276  			// TODO: check these two
   277  			ul.addNode(node, int(c.NodeAnnouncerIndex))
   278  			ul.addNode(ul.origin, int(c.NodeJoinerIndex))
   279  		}
   280  	}
   281  	return nil
   282  }