github.com/Hnampk/fabric@v2.1.1+incompatible/gossip/discovery/discovery.go (about)

     1  /*
     2  Copyright IBM Corp. 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  	proto "github.com/hyperledger/fabric-protos-go/gossip"
    14  	"github.com/hyperledger/fabric/gossip/common"
    15  	"github.com/hyperledger/fabric/gossip/protoext"
    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  // NetworkMember is a peer's representation
    77  type NetworkMember struct {
    78  	Endpoint         string
    79  	Metadata         []byte
    80  	PKIid            common.PKIidType
    81  	InternalEndpoint string
    82  	Properties       *proto.Properties
    83  	*proto.Envelope
    84  }
    85  
    86  // Clone clones the NetworkMember
    87  func (n NetworkMember) Clone() NetworkMember {
    88  	pkiIDClone := make(common.PKIidType, len(n.PKIid))
    89  	copy(pkiIDClone, n.PKIid)
    90  	nmClone := NetworkMember{
    91  		Endpoint:         n.Endpoint,
    92  		Metadata:         n.Metadata,
    93  		InternalEndpoint: n.InternalEndpoint,
    94  		PKIid:            pkiIDClone,
    95  	}
    96  
    97  	if n.Properties != nil {
    98  		nmClone.Properties = protolib.Clone(n.Properties).(*proto.Properties)
    99  	}
   100  
   101  	if n.Envelope != nil {
   102  		nmClone.Envelope = protolib.Clone(n.Envelope).(*proto.Envelope)
   103  	}
   104  
   105  	return nmClone
   106  }
   107  
   108  // String returns a string representation of the NetworkMember
   109  func (n NetworkMember) String() string {
   110  	return fmt.Sprintf("Endpoint: %s, InternalEndpoint: %s, PKI-ID: %s, Metadata: %x", n.Endpoint, n.InternalEndpoint, n.PKIid, n.Metadata)
   111  }
   112  
   113  // PreferredEndpoint computes the endpoint to connect to,
   114  // while preferring internal endpoint over the standard
   115  // endpoint
   116  func (n NetworkMember) PreferredEndpoint() string {
   117  	if n.InternalEndpoint != "" {
   118  		return n.InternalEndpoint
   119  	}
   120  	return n.Endpoint
   121  }
   122  
   123  // PeerIdentification encompasses a remote peer's
   124  // PKI-ID and whether its in the same org as the current
   125  // peer or not
   126  type PeerIdentification struct {
   127  	ID      common.PKIidType
   128  	SelfOrg bool
   129  }
   130  
   131  type identifier func() (*PeerIdentification, error)
   132  
   133  // Discovery is the interface that represents a discovery module
   134  type Discovery interface {
   135  	// Lookup returns a network member, or nil if not found
   136  	Lookup(PKIID common.PKIidType) *NetworkMember
   137  
   138  	// Self returns this instance's membership information
   139  	Self() NetworkMember
   140  
   141  	// UpdateMetadata updates this instance's metadata
   142  	UpdateMetadata([]byte)
   143  
   144  	// UpdateEndpoint updates this instance's endpoint
   145  	UpdateEndpoint(string)
   146  
   147  	// Stops this instance
   148  	Stop()
   149  
   150  	// GetMembership returns the alive members in the view
   151  	GetMembership() []NetworkMember
   152  
   153  	// InitiateSync makes the instance ask a given number of peers
   154  	// for their membership information
   155  	InitiateSync(peerNum int)
   156  
   157  	// Connect makes this instance to connect to a remote instance
   158  	// The identifier param is a function that can be used to identify
   159  	// the peer, and to assert its PKI-ID, whether its in the peer's org or not,
   160  	// and whether the action was successful or not
   161  	Connect(member NetworkMember, id identifier)
   162  }
   163  
   164  // Members represents an aggregation of NetworkMembers
   165  type Members []NetworkMember
   166  
   167  // ByID returns a mapping from the PKI-IDs (in string form)
   168  // to NetworkMember
   169  func (members Members) ByID() map[string]NetworkMember {
   170  	res := make(map[string]NetworkMember, len(members))
   171  	for _, peer := range members {
   172  		res[string(peer.PKIid)] = peer
   173  	}
   174  	return res
   175  }
   176  
   177  // Intersect returns the intersection of 2 Members
   178  func (members Members) Intersect(otherMembers Members) Members {
   179  	var res Members
   180  	m := otherMembers.ByID()
   181  	for _, member := range members {
   182  		if _, exists := m[string(member.PKIid)]; exists {
   183  			res = append(res, member)
   184  		}
   185  	}
   186  	return res
   187  }
   188  
   189  // Filter returns only members that satisfy the given filter
   190  func (members Members) Filter(filter func(member NetworkMember) bool) Members {
   191  	var res Members
   192  	for _, member := range members {
   193  		if filter(member) {
   194  			res = append(res, member)
   195  		}
   196  	}
   197  	return res
   198  }
   199  
   200  // Map invokes the given function to every NetworkMember among the Members
   201  func (members Members) Map(f func(member NetworkMember) NetworkMember) Members {
   202  	var res Members
   203  	for _, m := range members {
   204  		res = append(res, f(m))
   205  	}
   206  	return res
   207  }
   208  
   209  // HaveExternalEndpoints selects network members that have external endpoints
   210  func HasExternalEndpoint(member NetworkMember) bool {
   211  	return member.Endpoint != ""
   212  }