github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/gossip/state/state.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package state
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"sync"
    24  	"sync/atomic"
    25  	"time"
    26  
    27  	pb "github.com/golang/protobuf/proto"
    28  	"github.com/hyperledger/fabric/core/committer"
    29  	"github.com/hyperledger/fabric/gossip/api"
    30  	"github.com/hyperledger/fabric/gossip/comm"
    31  	common2 "github.com/hyperledger/fabric/gossip/common"
    32  	"github.com/hyperledger/fabric/gossip/discovery"
    33  	"github.com/hyperledger/fabric/gossip/util"
    34  	"github.com/hyperledger/fabric/protos/common"
    35  	proto "github.com/hyperledger/fabric/protos/gossip"
    36  	"github.com/op/go-logging"
    37  	"github.com/spf13/viper"
    38  )
    39  
    40  // GossipStateProvider is the interface to acquire sequences of the ledger blocks
    41  // capable to full fill missing blocks by running state replication and
    42  // sending request to get missing block to other nodes
    43  type GossipStateProvider interface {
    44  	// Retrieve block with sequence number equal to index
    45  	GetBlock(index uint64) *common.Block
    46  
    47  	AddPayload(payload *proto.Payload) error
    48  
    49  	// Stop terminates state transfer object
    50  	Stop()
    51  }
    52  
    53  const (
    54  	defAntiEntropyInterval             = 10 * time.Second
    55  	defAntiEntropyStateResponseTimeout = 3 * time.Second
    56  	defAntiEntropyBatchSize            = 10
    57  
    58  	defChannelBufferSize     = 100
    59  	defAntiEntropyMaxRetries = 3
    60  
    61  	defMaxBlockDistance = 100
    62  
    63  	blocking    = true
    64  	nonBlocking = false
    65  
    66  	enqueueRetryInterval = time.Millisecond * 100
    67  )
    68  
    69  // GossipAdapter defines gossip/communication required interface for state provider
    70  type GossipAdapter interface {
    71  	// Send sends a message to remote peers
    72  	Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
    73  
    74  	// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
    75  	// If passThrough is false, the messages are processed by the gossip layer beforehand.
    76  	// If passThrough is true, the gossip layer doesn't intervene and the messages
    77  	// can be used to send a reply back to the sender
    78  	Accept(acceptor common2.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
    79  
    80  	// UpdateChannelMetadata updates the self metadata the peer
    81  	// publishes to other peers about its channel-related state
    82  	UpdateChannelMetadata(metadata []byte, chainID common2.ChainID)
    83  
    84  	// PeersOfChannel returns the NetworkMembers considered alive
    85  	// and also subscribed to the channel given
    86  	PeersOfChannel(common2.ChainID) []discovery.NetworkMember
    87  }
    88  
    89  // GossipStateProviderImpl the implementation of the GossipStateProvider interface
    90  // the struct to handle in memory sliding window of
    91  // new ledger block to be acquired by hyper ledger
    92  type GossipStateProviderImpl struct {
    93  	// MessageCryptoService
    94  	mcs api.MessageCryptoService
    95  
    96  	// Chain id
    97  	chainID string
    98  
    99  	// The gossiping service
   100  	gossip GossipAdapter
   101  
   102  	// Channel to read gossip messages from
   103  	gossipChan <-chan *proto.GossipMessage
   104  
   105  	commChan <-chan proto.ReceivedMessage
   106  
   107  	// Queue of payloads which wasn't acquired yet
   108  	payloads PayloadsBuffer
   109  
   110  	committer committer.Committer
   111  
   112  	stateResponseCh chan proto.ReceivedMessage
   113  
   114  	stateRequestCh chan proto.ReceivedMessage
   115  
   116  	stopCh chan struct{}
   117  
   118  	done sync.WaitGroup
   119  
   120  	once sync.Once
   121  
   122  	stateTransferActive int32
   123  }
   124  
   125  var logger *logging.Logger // package-level logger
   126  
   127  func init() {
   128  	logger = util.GetLogger(util.LoggingStateModule, "")
   129  }
   130  
   131  // NewGossipStateProvider creates initialized instance of gossip state provider
   132  func NewGossipStateProvider(chainID string, g GossipAdapter, committer committer.Committer, mcs api.MessageCryptoService) GossipStateProvider {
   133  	logger := util.GetLogger(util.LoggingStateModule, "")
   134  
   135  	gossipChan, _ := g.Accept(func(message interface{}) bool {
   136  		// Get only data messages
   137  		return message.(*proto.GossipMessage).IsDataMsg() &&
   138  			bytes.Equal(message.(*proto.GossipMessage).Channel, []byte(chainID))
   139  	}, false)
   140  
   141  	remoteStateMsgFilter := func(message interface{}) bool {
   142  		receivedMsg := message.(proto.ReceivedMessage)
   143  		msg := receivedMsg.GetGossipMessage()
   144  		if !msg.IsRemoteStateMessage() {
   145  			return false
   146  		}
   147  		// If we're not running with authentication, no point
   148  		// in enforcing access control
   149  		if !receivedMsg.GetConnectionInfo().IsAuthenticated() {
   150  			return true
   151  		}
   152  		connInfo := receivedMsg.GetConnectionInfo()
   153  		authErr := mcs.VerifyByChannel(msg.Channel, connInfo.Identity, connInfo.Auth.Signature, connInfo.Auth.SignedData)
   154  		if authErr != nil {
   155  			logger.Warning("Got unauthorized nodeMetastate transfer request from", string(connInfo.Identity))
   156  			return false
   157  		}
   158  		return true
   159  	}
   160  
   161  	// Filter message which are only relevant for nodeMetastate transfer
   162  	_, commChan := g.Accept(remoteStateMsgFilter, true)
   163  
   164  	height, err := committer.LedgerHeight()
   165  	if height == 0 {
   166  		// Panic here since this is an indication of invalid situation which should not happen in normal
   167  		// code path.
   168  		logger.Panic("Committer height cannot be zero, ledger should include at least one block (genesis).")
   169  	}
   170  
   171  	if err != nil {
   172  		logger.Error("Could not read ledger info to obtain current ledger height due to: ", err)
   173  		// Exiting as without ledger it will be impossible
   174  		// to deliver new blocks
   175  		return nil
   176  	}
   177  
   178  	s := &GossipStateProviderImpl{
   179  		// MessageCryptoService
   180  		mcs: mcs,
   181  
   182  		// Chain ID
   183  		chainID: chainID,
   184  
   185  		// Instance of the gossip
   186  		gossip: g,
   187  
   188  		// Channel to read new messages from
   189  		gossipChan: gossipChan,
   190  
   191  		// Channel to read direct messages from other peers
   192  		commChan: commChan,
   193  
   194  		// Create a queue for payload received
   195  		payloads: NewPayloadsBuffer(height),
   196  
   197  		committer: committer,
   198  
   199  		stateResponseCh: make(chan proto.ReceivedMessage, defChannelBufferSize),
   200  
   201  		stateRequestCh: make(chan proto.ReceivedMessage, defChannelBufferSize),
   202  
   203  		stopCh: make(chan struct{}, 1),
   204  
   205  		stateTransferActive: 0,
   206  
   207  		once: sync.Once{},
   208  	}
   209  
   210  	nodeMetastate := NewNodeMetastate(height - 1)
   211  
   212  	logger.Infof("Updating node metadata information, "+
   213  		"current ledger sequence is at = %d, next expected block is = %d", nodeMetastate.LedgerHeight, s.payloads.Next())
   214  
   215  	b, err := nodeMetastate.Bytes()
   216  	if err == nil {
   217  		logger.Debug("Updating gossip metadate nodeMetastate", nodeMetastate)
   218  		g.UpdateChannelMetadata(b, common2.ChainID(s.chainID))
   219  	} else {
   220  		logger.Errorf("Unable to serialize node meta nodeMetastate, error = %s", err)
   221  	}
   222  
   223  	s.done.Add(4)
   224  
   225  	// Listen for incoming communication
   226  	go s.listen()
   227  	// Deliver in order messages into the incoming channel
   228  	go s.deliverPayloads()
   229  	// Execute anti entropy to fill missing gaps
   230  	go s.antiEntropy()
   231  	// Taking care of state request messages
   232  	go s.processStateRequests()
   233  
   234  	return s
   235  }
   236  
   237  func (s *GossipStateProviderImpl) listen() {
   238  	defer s.done.Done()
   239  
   240  	for {
   241  		select {
   242  		case msg := <-s.gossipChan:
   243  			logger.Debug("Received new message via gossip channel")
   244  			go s.queueNewMessage(msg)
   245  		case msg := <-s.commChan:
   246  			logger.Debug("Direct message ", msg)
   247  			go s.directMessage(msg)
   248  		case <-s.stopCh:
   249  			s.stopCh <- struct{}{}
   250  			logger.Debug("Stop listening for new messages")
   251  			return
   252  		}
   253  	}
   254  }
   255  
   256  func (s *GossipStateProviderImpl) directMessage(msg proto.ReceivedMessage) {
   257  	logger.Debug("[ENTER] -> directMessage")
   258  	defer logger.Debug("[EXIT] ->  directMessage")
   259  
   260  	if msg == nil {
   261  		logger.Error("Got nil message via end-to-end channel, should not happen!")
   262  		return
   263  	}
   264  
   265  	if !bytes.Equal(msg.GetGossipMessage().Channel, []byte(s.chainID)) {
   266  		logger.Warning("Received state transfer request for channel",
   267  			string(msg.GetGossipMessage().Channel), "while expecting channel", s.chainID, "skipping request...")
   268  		return
   269  	}
   270  
   271  	incoming := msg.GetGossipMessage()
   272  
   273  	if incoming.GetStateRequest() != nil {
   274  		if len(s.stateRequestCh) < defChannelBufferSize {
   275  			// Forward state request to the channel, if there are too
   276  			// many message of state request ignore to avoid flooding.
   277  			s.stateRequestCh <- msg
   278  		}
   279  	} else if incoming.GetStateResponse() != nil {
   280  		// If no state transfer procedure activate there is
   281  		// no reason to process the message
   282  		if atomic.LoadInt32(&s.stateTransferActive) == 1 {
   283  			// Send signal of state response message
   284  			s.stateResponseCh <- msg
   285  		}
   286  	}
   287  }
   288  
   289  func (s *GossipStateProviderImpl) processStateRequests() {
   290  	defer s.done.Done()
   291  
   292  	for {
   293  		select {
   294  		case msg := <-s.stateRequestCh:
   295  			s.handleStateRequest(msg)
   296  		case <-s.stopCh:
   297  			s.stopCh <- struct{}{}
   298  			return
   299  		}
   300  	}
   301  }
   302  
   303  // Handle state request message, validate batch size, read current leader state to
   304  // obtain required blocks, build response message and send it back
   305  func (s *GossipStateProviderImpl) handleStateRequest(msg proto.ReceivedMessage) {
   306  	if msg == nil {
   307  		return
   308  	}
   309  	request := msg.GetGossipMessage().GetStateRequest()
   310  
   311  	batchSize := request.EndSeqNum - request.StartSeqNum
   312  	if batchSize > defAntiEntropyBatchSize {
   313  		logger.Errorf("Requesting blocks batchSize size (%d) greater than configured allowed"+
   314  			" (%d) batching for anti-entropy. Ignoring request...", batchSize, defAntiEntropyBatchSize)
   315  		return
   316  	}
   317  
   318  	if request.StartSeqNum > request.EndSeqNum {
   319  		logger.Errorf("Invalid sequence interval [%d...%d], ignoring request...", request.StartSeqNum, request.EndSeqNum)
   320  		return
   321  	}
   322  
   323  	currentHeight, err := s.committer.LedgerHeight()
   324  	if err != nil {
   325  		logger.Errorf("Cannot access to current ledger height, due to %s", err)
   326  		return
   327  	}
   328  	if currentHeight < request.EndSeqNum {
   329  		logger.Warningf("Received state request to transfer blocks with sequence numbers higher  [%d...%d] "+
   330  			"than available in ledger (%d)", request.StartSeqNum, request.StartSeqNum, currentHeight)
   331  	}
   332  
   333  	endSeqNum := min(currentHeight, request.EndSeqNum)
   334  
   335  	response := &proto.RemoteStateResponse{Payloads: make([]*proto.Payload, 0)}
   336  	for seqNum := request.StartSeqNum; seqNum <= endSeqNum; seqNum++ {
   337  		logger.Debug("Reading block ", seqNum, " from the committer service")
   338  		blocks := s.committer.GetBlocks([]uint64{seqNum})
   339  
   340  		if len(blocks) == 0 {
   341  			logger.Errorf("Wasn't able to read block with sequence number %d from ledger, skipping....", seqNum)
   342  			continue
   343  		}
   344  
   345  		blockBytes, err := pb.Marshal(blocks[0])
   346  		if err != nil {
   347  			logger.Errorf("Could not marshal block: %s", err)
   348  		}
   349  
   350  		response.Payloads = append(response.Payloads, &proto.Payload{
   351  			SeqNum: seqNum,
   352  			Data:   blockBytes,
   353  		})
   354  	}
   355  	// Sending back response with missing blocks
   356  	msg.Respond(&proto.GossipMessage{
   357  		// Copy nonce field from the request, so it will be possible to match response
   358  		Nonce:   msg.GetGossipMessage().Nonce,
   359  		Tag:     proto.GossipMessage_CHAN_OR_ORG,
   360  		Channel: []byte(s.chainID),
   361  		Content: &proto.GossipMessage_StateResponse{response},
   362  	})
   363  }
   364  
   365  func (s *GossipStateProviderImpl) handleStateResponse(msg proto.ReceivedMessage) (uint64, error) {
   366  	max := uint64(0)
   367  	// Send signal that response for given nonce has been received
   368  	response := msg.GetGossipMessage().GetStateResponse()
   369  	// Extract payloads, verify and push into buffer
   370  	if len(response.GetPayloads()) == 0 {
   371  		return uint64(0), errors.New("Received state tranfer response without payload")
   372  	}
   373  	for _, payload := range response.GetPayloads() {
   374  		logger.Debugf("Received payload with sequence number %d.", payload.SeqNum)
   375  		if err := s.mcs.VerifyBlock(common2.ChainID(s.chainID), payload.SeqNum, payload.Data); err != nil {
   376  			logger.Warningf("Error verifying block with sequence number %d, due to %s", payload.SeqNum, err)
   377  			return uint64(0), err
   378  		}
   379  		if max < payload.SeqNum {
   380  			max = payload.SeqNum
   381  		}
   382  
   383  		err := s.addPayload(payload, blocking)
   384  		if err != nil {
   385  			logger.Warningf("Payload with sequence number %d wasn't added to payload buffer: %v", payload.SeqNum, err)
   386  		}
   387  	}
   388  	return max, nil
   389  }
   390  
   391  // Stop function send halting signal to all go routines
   392  func (s *GossipStateProviderImpl) Stop() {
   393  	// Make sure stop won't be executed twice
   394  	// and stop channel won't be used again
   395  	s.once.Do(func() {
   396  		s.stopCh <- struct{}{}
   397  		// Make sure all go-routines has finished
   398  		s.done.Wait()
   399  		// Close all resources
   400  		s.committer.Close()
   401  		close(s.stateRequestCh)
   402  		close(s.stateResponseCh)
   403  		close(s.stopCh)
   404  	})
   405  }
   406  
   407  // New message notification/handler
   408  func (s *GossipStateProviderImpl) queueNewMessage(msg *proto.GossipMessage) {
   409  	if !bytes.Equal(msg.Channel, []byte(s.chainID)) {
   410  		logger.Warning("Received enqueue for channel",
   411  			string(msg.Channel), "while expecting channel", s.chainID, "ignoring enqueue")
   412  		return
   413  	}
   414  
   415  	dataMsg := msg.GetDataMsg()
   416  	if dataMsg != nil {
   417  		if err := s.addPayload(dataMsg.GetPayload(), nonBlocking); err != nil {
   418  			logger.Warning("Failed adding payload:", err)
   419  			return
   420  		}
   421  		logger.Debugf("Received new payload with sequence number = [%d]", dataMsg.Payload.SeqNum)
   422  	} else {
   423  		logger.Debug("Gossip message received is not of data message type, usually this should not happen.")
   424  	}
   425  }
   426  
   427  func (s *GossipStateProviderImpl) deliverPayloads() {
   428  	defer s.done.Done()
   429  
   430  	for {
   431  		select {
   432  		// Wait for notification that next seq has arrived
   433  		case <-s.payloads.Ready():
   434  			logger.Debugf("Ready to transfer payloads to the ledger, next sequence number is = [%d]", s.payloads.Next())
   435  			// Collect all subsequent payloads
   436  			for payload := s.payloads.Pop(); payload != nil; payload = s.payloads.Pop() {
   437  				rawBlock := &common.Block{}
   438  				if err := pb.Unmarshal(payload.Data, rawBlock); err != nil {
   439  					logger.Errorf("Error getting block with seqNum = %d due to (%s)...dropping block", payload.SeqNum, err)
   440  					continue
   441  				}
   442  				if rawBlock.Data == nil || rawBlock.Header == nil {
   443  					logger.Errorf("Block with claimed sequence %d has no header (%v) or data (%v)",
   444  						payload.SeqNum, rawBlock.Header, rawBlock.Data)
   445  					continue
   446  				}
   447  				logger.Debug("New block with claimed sequence number ", payload.SeqNum, " transactions num ", len(rawBlock.Data.Data))
   448  				if err := s.commitBlock(rawBlock); err != nil {
   449  					logger.Panicf("Cannot commit block to the ledger due to %s", err)
   450  				}
   451  			}
   452  		case <-s.stopCh:
   453  			s.stopCh <- struct{}{}
   454  			logger.Debug("State provider has been stoped, finishing to push new blocks.")
   455  			return
   456  		}
   457  	}
   458  }
   459  
   460  func (s *GossipStateProviderImpl) antiEntropy() {
   461  	defer s.done.Done()
   462  	defer logger.Debug("State Provider stopped, stopping anti entropy procedure.")
   463  
   464  	for {
   465  		select {
   466  		case <-s.stopCh:
   467  			s.stopCh <- struct{}{}
   468  			return
   469  		case <-time.After(defAntiEntropyInterval):
   470  			current, err := s.committer.LedgerHeight()
   471  			if err != nil {
   472  				// Unable to read from ledger continue to the next round
   473  				logger.Error("Cannot obtain ledger height, due to", err)
   474  				continue
   475  			}
   476  			if current == 0 {
   477  				logger.Error("Ledger reported block height of 0 but this should be impossible")
   478  				continue
   479  			}
   480  			max := s.maxAvailableLedgerHeight()
   481  
   482  			if current-1 >= max {
   483  				continue
   484  			}
   485  
   486  			s.requestBlocksInRange(uint64(current), uint64(max))
   487  		}
   488  	}
   489  }
   490  
   491  // Iterate over all available peers and check advertised meta state to
   492  // find maximum available ledger height across peers
   493  func (s *GossipStateProviderImpl) maxAvailableLedgerHeight() uint64 {
   494  	max := uint64(0)
   495  	for _, p := range s.gossip.PeersOfChannel(common2.ChainID(s.chainID)) {
   496  		if nodeMetastate, err := FromBytes(p.Metadata); err == nil {
   497  			if max < nodeMetastate.LedgerHeight {
   498  				max = nodeMetastate.LedgerHeight
   499  			}
   500  		}
   501  	}
   502  	return max
   503  }
   504  
   505  // GetBlocksInRange capable to acquire blocks with sequence
   506  // numbers in the range [start...end].
   507  func (s *GossipStateProviderImpl) requestBlocksInRange(start uint64, end uint64) {
   508  	atomic.StoreInt32(&s.stateTransferActive, 1)
   509  	defer atomic.StoreInt32(&s.stateTransferActive, 0)
   510  
   511  	for prev := start; prev <= end; {
   512  		next := min(end, prev+defAntiEntropyBatchSize)
   513  
   514  		gossipMsg := s.stateRequestMessage(prev, next)
   515  
   516  		responseReceived := false
   517  		tryCounts := 0
   518  
   519  		for !responseReceived {
   520  			if tryCounts > defAntiEntropyMaxRetries {
   521  				logger.Warningf("Wasn't  able to get blocks in range [%d...%d], after %d retries",
   522  					prev, next, tryCounts)
   523  				return
   524  			}
   525  			// Select peers to ask for blocks
   526  			peer, err := s.selectPeerToRequestFrom(next)
   527  			if err != nil {
   528  				logger.Warningf("Cannot send state request for blocks in range [%d...%d], due to",
   529  					prev, next, err)
   530  				return
   531  			}
   532  
   533  			logger.Debugf("State transfer, with peer %s, requesting blocks in range [%d...%d], "+
   534  				"for chainID %s", peer.Endpoint, prev, next, s.chainID)
   535  
   536  			s.gossip.Send(gossipMsg, peer)
   537  			tryCounts++
   538  
   539  			// Wait until timeout or response arrival
   540  			select {
   541  			case msg := <-s.stateResponseCh:
   542  				if msg.GetGossipMessage().Nonce != gossipMsg.Nonce {
   543  					continue
   544  				}
   545  				// Got corresponding response for state request, can continue
   546  				index, err := s.handleStateResponse(msg)
   547  				if err != nil {
   548  					logger.Warningf("Wasn't able to process state response for "+
   549  						"blocks [%d...%d], due to %s", prev, next, err)
   550  					continue
   551  				}
   552  				prev = index + 1
   553  				responseReceived = true
   554  			case <-time.After(defAntiEntropyStateResponseTimeout):
   555  			case <-s.stopCh:
   556  				s.stopCh <- struct{}{}
   557  				return
   558  			}
   559  		}
   560  	}
   561  }
   562  
   563  // Generate state request message for given blocks in range [beginSeq...endSeq]
   564  func (s *GossipStateProviderImpl) stateRequestMessage(beginSeq uint64, endSeq uint64) *proto.GossipMessage {
   565  	return &proto.GossipMessage{
   566  		Nonce:   util.RandomUInt64(),
   567  		Tag:     proto.GossipMessage_CHAN_OR_ORG,
   568  		Channel: []byte(s.chainID),
   569  		Content: &proto.GossipMessage_StateRequest{
   570  			StateRequest: &proto.RemoteStateRequest{
   571  				StartSeqNum: beginSeq,
   572  				EndSeqNum:   endSeq,
   573  			},
   574  		},
   575  	}
   576  }
   577  
   578  // Select peer which has required blocks to ask missing blocks from
   579  func (s *GossipStateProviderImpl) selectPeerToRequestFrom(height uint64) (*comm.RemotePeer, error) {
   580  	// Filter peers which posses required range of missing blocks
   581  	peers := s.filterPeers(s.hasRequiredHeight(height))
   582  
   583  	n := len(peers)
   584  	if n == 0 {
   585  		return nil, errors.New("there are no peers to ask for missing blocks from")
   586  	}
   587  
   588  	// Select peers to ask for blocks
   589  	return peers[util.RandomInt(n)], nil
   590  }
   591  
   592  // filterPeers return list of peers which aligns the predicate provided
   593  func (s *GossipStateProviderImpl) filterPeers(predicate func(peer discovery.NetworkMember) bool) []*comm.RemotePeer {
   594  	var peers []*comm.RemotePeer
   595  
   596  	for _, member := range s.gossip.PeersOfChannel(common2.ChainID(s.chainID)) {
   597  		if predicate(member) {
   598  			peers = append(peers, &comm.RemotePeer{Endpoint: member.PreferredEndpoint(), PKIID: member.PKIid})
   599  		}
   600  	}
   601  
   602  	return peers
   603  }
   604  
   605  // hasRequiredHeight returns predicate which is capable to filter peers with ledger height above than indicated
   606  // by provided input parameter
   607  func (s *GossipStateProviderImpl) hasRequiredHeight(height uint64) func(peer discovery.NetworkMember) bool {
   608  	return func(peer discovery.NetworkMember) bool {
   609  		if nodeMetadata, err := FromBytes(peer.Metadata); err != nil {
   610  			logger.Errorf("Unable to de-serialize node meta state, error = %s", err)
   611  		} else if nodeMetadata.LedgerHeight >= height {
   612  			return true
   613  		}
   614  
   615  		return false
   616  	}
   617  }
   618  
   619  // GetBlock return ledger block given its sequence number as a parameter
   620  func (s *GossipStateProviderImpl) GetBlock(index uint64) *common.Block {
   621  	// Try to read missing block from the ledger, should return no nil with
   622  	// content including at least one block
   623  	if blocks := s.committer.GetBlocks([]uint64{index}); blocks != nil && len(blocks) > 0 {
   624  		return blocks[0]
   625  	}
   626  
   627  	return nil
   628  }
   629  
   630  // AddPayload add new payload into state.
   631  func (s *GossipStateProviderImpl) AddPayload(payload *proto.Payload) error {
   632  	blockingMode := blocking
   633  	if viper.GetBool("peer.gossip.nonBlockingCommitMode") {
   634  		blockingMode = false
   635  	}
   636  	return s.addPayload(payload, blockingMode)
   637  }
   638  
   639  // addPayload add new payload into state. It may (or may not) block according to the
   640  // given parameter. If it gets a block while in blocking mode - it would wait until
   641  // the block is sent into the payloads buffer.
   642  // Else - it may drop the block, if the payload buffer is too full.
   643  func (s *GossipStateProviderImpl) addPayload(payload *proto.Payload, blockingMode bool) error {
   644  	if payload == nil {
   645  		return errors.New("Given payload is nil")
   646  	}
   647  	logger.Debug("Adding new payload into the buffer, seqNum = ", payload.SeqNum)
   648  	height, err := s.committer.LedgerHeight()
   649  	if err != nil {
   650  		return fmt.Errorf("Failed obtaining ledger height: %v", err)
   651  	}
   652  
   653  	if !blockingMode && payload.SeqNum-height >= defMaxBlockDistance {
   654  		return fmt.Errorf("Ledger height is at %d, cannot enqueue block with sequence of %d", height, payload.SeqNum)
   655  	}
   656  
   657  	for blockingMode && s.payloads.Size() > defMaxBlockDistance*2 {
   658  		time.Sleep(enqueueRetryInterval)
   659  	}
   660  
   661  	return s.payloads.Push(payload)
   662  }
   663  
   664  func (s *GossipStateProviderImpl) commitBlock(block *common.Block) error {
   665  	if err := s.committer.Commit(block); err != nil {
   666  		logger.Errorf("Got error while committing(%s)", err)
   667  		return err
   668  	}
   669  
   670  	// Update ledger level within node metadata
   671  	nodeMetastate := NewNodeMetastate(block.Header.Number)
   672  	// Decode nodeMetastate to byte array
   673  	b, err := nodeMetastate.Bytes()
   674  	if err == nil {
   675  		s.gossip.UpdateChannelMetadata(b, common2.ChainID(s.chainID))
   676  	} else {
   677  
   678  		logger.Errorf("Unable to serialize node meta nodeMetastate, error = %s", err)
   679  	}
   680  
   681  	logger.Debugf("Channel [%s]: Created block [%d] with %d transaction(s)",
   682  		s.chainID, block.Header.Number, len(block.Data.Data))
   683  
   684  	return nil
   685  }
   686  
   687  func min(a uint64, b uint64) uint64 {
   688  	return b ^ ((a ^ b) & (-(uint64(a-b) >> 63)))
   689  }