github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/discovery/discovery.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package discovery
     8  
     9  import (
    10  	"fmt"
    11  
    12  	protolib "github.com/golang/protobuf/proto"
    13  	"github.com/hechain20/hechain/gossip/common"
    14  	"github.com/hechain20/hechain/gossip/protoext"
    15  	proto "github.com/hyperledger/fabric-protos-go/gossip"
    16  )
    17  
    18  // CryptoService is an interface that the discovery expects to be implemented and passed on creation
    19  type CryptoService interface {
    20  	// ValidateAliveMsg validates that an Alive message is authentic
    21  	ValidateAliveMsg(message *protoext.SignedGossipMessage) bool
    22  
    23  	// SignMessage signs a message
    24  	SignMessage(m *proto.GossipMessage, internalEndpoint string) *proto.Envelope
    25  }
    26  
    27  // EnvelopeFilter may or may not remove part of the Envelope
    28  // that the given SignedGossipMessage originates from.
    29  type EnvelopeFilter func(message *protoext.SignedGossipMessage) *proto.Envelope
    30  
    31  // Sieve defines the messages that are allowed to be sent to some remote peer,
    32  // based on some criteria.
    33  // Returns whether the sieve permits sending a given message.
    34  type Sieve func(message *protoext.SignedGossipMessage) bool
    35  
    36  // DisclosurePolicy defines which messages a given remote peer
    37  // is eligible of knowing about, and also what is it eligible
    38  // to know about out of a given SignedGossipMessage.
    39  // Returns:
    40  // 1) A Sieve for a given remote peer.
    41  //    The Sieve is applied for each peer in question and outputs
    42  //    whether the message should be disclosed to the remote peer.
    43  // 2) A EnvelopeFilter for a given SignedGossipMessage, which may remove
    44  //    part of the Envelope the SignedGossipMessage originates from
    45  type DisclosurePolicy func(remotePeer *NetworkMember) (Sieve, EnvelopeFilter)
    46  
    47  // CommService is an interface that the discovery expects to be implemented and passed on creation
    48  type CommService interface {
    49  	// Gossip gossips a message
    50  	Gossip(msg *protoext.SignedGossipMessage)
    51  
    52  	// SendToPeer sends to a given peer a message.
    53  	// The nonce can be anything since the communication module handles the nonce itself
    54  	SendToPeer(peer *NetworkMember, msg *protoext.SignedGossipMessage)
    55  
    56  	// Ping probes a remote peer and returns if it's responsive or not
    57  	Ping(peer *NetworkMember) bool
    58  
    59  	// Accept returns a read-only channel for membership messages sent from remote peers
    60  	Accept() <-chan protoext.ReceivedMessage
    61  
    62  	// PresumedDead returns a read-only channel for peers that are presumed to be dead
    63  	PresumedDead() <-chan common.PKIidType
    64  
    65  	// CloseConn orders to close the connection with a certain peer
    66  	CloseConn(peer *NetworkMember)
    67  
    68  	// Forward sends message to the next hop, excluding the hop
    69  	// from which message was initially received
    70  	Forward(msg protoext.ReceivedMessage)
    71  
    72  	// IdentitySwitch returns a read-only channel about identity change events
    73  	IdentitySwitch() <-chan common.PKIidType
    74  }
    75  
    76  // AnchorPeerTracker is an interface that is passed to discovery to check if an endpoint is an anchor peer
    77  type AnchorPeerTracker interface {
    78  	IsAnchorPeer(endpoint string) bool
    79  }
    80  
    81  // NetworkMember is a peer's representation
    82  type NetworkMember struct {
    83  	Endpoint         string
    84  	Metadata         []byte
    85  	PKIid            common.PKIidType
    86  	InternalEndpoint string
    87  	Properties       *proto.Properties
    88  	*proto.Envelope
    89  }
    90  
    91  // Clone clones the NetworkMember
    92  func (n NetworkMember) Clone() NetworkMember {
    93  	pkiIDClone := make(common.PKIidType, len(n.PKIid))
    94  	copy(pkiIDClone, n.PKIid)
    95  	nmClone := NetworkMember{
    96  		Endpoint:         n.Endpoint,
    97  		Metadata:         n.Metadata,
    98  		InternalEndpoint: n.InternalEndpoint,
    99  		PKIid:            pkiIDClone,
   100  	}
   101  
   102  	if n.Properties != nil {
   103  		nmClone.Properties = protolib.Clone(n.Properties).(*proto.Properties)
   104  	}
   105  
   106  	if n.Envelope != nil {
   107  		nmClone.Envelope = protolib.Clone(n.Envelope).(*proto.Envelope)
   108  	}
   109  
   110  	return nmClone
   111  }
   112  
   113  // String returns a string representation of the NetworkMember
   114  func (n NetworkMember) String() string {
   115  	return fmt.Sprintf("Endpoint: %s, InternalEndpoint: %s, PKI-ID: %s, Metadata: %x", n.Endpoint, n.InternalEndpoint, n.PKIid, n.Metadata)
   116  }
   117  
   118  // PreferredEndpoint computes the endpoint to connect to,
   119  // while preferring internal endpoint over the standard
   120  // endpoint
   121  func (n NetworkMember) PreferredEndpoint() string {
   122  	if n.InternalEndpoint != "" {
   123  		return n.InternalEndpoint
   124  	}
   125  	return n.Endpoint
   126  }
   127  
   128  // PeerIdentification encompasses a remote peer's
   129  // PKI-ID and whether its in the same org as the current
   130  // peer or not
   131  type PeerIdentification struct {
   132  	ID      common.PKIidType
   133  	SelfOrg bool
   134  }
   135  
   136  type identifier func() (*PeerIdentification, error)
   137  
   138  // Discovery is the interface that represents a discovery module
   139  type Discovery interface {
   140  	// Lookup returns a network member, or nil if not found
   141  	Lookup(PKIID common.PKIidType) *NetworkMember
   142  
   143  	// Self returns this instance's membership information
   144  	Self() NetworkMember
   145  
   146  	// UpdateMetadata updates this instance's metadata
   147  	UpdateMetadata([]byte)
   148  
   149  	// UpdateEndpoint updates this instance's endpoint
   150  	UpdateEndpoint(string)
   151  
   152  	// Stops this instance
   153  	Stop()
   154  
   155  	// GetMembership returns the alive members in the view
   156  	GetMembership() []NetworkMember
   157  
   158  	// InitiateSync makes the instance ask a given number of peers
   159  	// for their membership information
   160  	InitiateSync(peerNum int)
   161  
   162  	// Connect makes this instance to connect to a remote instance
   163  	// The identifier param is a function that can be used to identify
   164  	// the peer, and to assert its PKI-ID, whether its in the peer's org or not,
   165  	// and whether the action was successful or not
   166  	Connect(member NetworkMember, id identifier)
   167  }
   168  
   169  // Members represents an aggregation of NetworkMembers
   170  type Members []NetworkMember
   171  
   172  // ByID returns a mapping from the PKI-IDs (in string form)
   173  // to NetworkMember
   174  func (members Members) ByID() map[string]NetworkMember {
   175  	res := make(map[string]NetworkMember, len(members))
   176  	for _, peer := range members {
   177  		res[string(peer.PKIid)] = peer
   178  	}
   179  	return res
   180  }
   181  
   182  // Intersect returns the intersection of 2 Members
   183  func (members Members) Intersect(otherMembers Members) Members {
   184  	var res Members
   185  	m := otherMembers.ByID()
   186  	for _, member := range members {
   187  		if _, exists := m[string(member.PKIid)]; exists {
   188  			res = append(res, member)
   189  		}
   190  	}
   191  	return res
   192  }
   193  
   194  // Filter returns only members that satisfy the given filter
   195  func (members Members) Filter(filter func(member NetworkMember) bool) Members {
   196  	var res Members
   197  	for _, member := range members {
   198  		if filter(member) {
   199  			res = append(res, member)
   200  		}
   201  	}
   202  	return res
   203  }
   204  
   205  // Map invokes the given function to every NetworkMember among the Members
   206  func (members Members) Map(f func(member NetworkMember) NetworkMember) Members {
   207  	var res Members
   208  	for _, m := range members {
   209  		res = append(res, f(m))
   210  	}
   211  	return res
   212  }
   213  
   214  // HaveExternalEndpoints selects network members that have external endpoints
   215  func HasExternalEndpoint(member NetworkMember) bool {
   216  	return member.Endpoint != ""
   217  }