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