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