github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/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 "sync" 12 "sync/atomic" 13 "time" 14 15 pb "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric-protos-go/common" 17 proto "github.com/hyperledger/fabric-protos-go/gossip" 18 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 19 "github.com/hyperledger/fabric-protos-go/peer" 20 "github.com/hyperledger/fabric-protos-go/transientstore" 21 vsccErrors "github.com/hyperledger/fabric/common/errors" 22 "github.com/hyperledger/fabric/gossip/api" 23 "github.com/hyperledger/fabric/gossip/comm" 24 common2 "github.com/hyperledger/fabric/gossip/common" 25 "github.com/hyperledger/fabric/gossip/discovery" 26 "github.com/hyperledger/fabric/gossip/metrics" 27 "github.com/hyperledger/fabric/gossip/protoext" 28 "github.com/hyperledger/fabric/gossip/util" 29 "github.com/hyperledger/fabric/protoutil" 30 "github.com/pkg/errors" 31 ) 32 33 // GossipStateProvider is the interface to acquire sequences of the ledger blocks 34 // capable to full fill missing blocks by running state replication and 35 // sending request to get missing block to other nodes 36 type GossipStateProvider interface { 37 AddPayload(payload *proto.Payload) error 38 39 // Stop terminates state transfer object 40 Stop() 41 } 42 43 const ( 44 defAntiEntropyInterval = 10 * time.Second 45 defAntiEntropyStateResponseTimeout = 3 * time.Second 46 defAntiEntropyBatchSize = 10 47 48 defChannelBufferSize = 100 49 defAntiEntropyMaxRetries = 3 50 51 defMaxBlockDistance = 100 52 53 blocking = true 54 nonBlocking = false 55 56 enqueueRetryInterval = time.Millisecond * 100 57 ) 58 59 // Configuration keeps state transfer configuration parameters 60 type Configuration struct { 61 AntiEntropyInterval time.Duration 62 AntiEntropyStateResponseTimeout time.Duration 63 AntiEntropyBatchSize uint64 64 MaxBlockDistance int 65 AntiEntropyMaxRetries int 66 ChannelBufferSize int 67 EnableStateTransfer bool 68 } 69 70 // GossipAdapter defines gossip/communication required interface for state provider 71 type GossipAdapter interface { 72 // Send sends a message to remote peers 73 Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer) 74 75 // Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate. 76 // If passThrough is false, the messages are processed by the gossip layer beforehand. 77 // If passThrough is true, the gossip layer doesn't intervene and the messages 78 // can be used to send a reply back to the sender 79 Accept(acceptor common2.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan protoext.ReceivedMessage) 80 81 // UpdateLedgerHeight updates the ledger height the peer 82 // publishes to other peers in the channel 83 UpdateLedgerHeight(height uint64, channelID common2.ChannelID) 84 85 // PeersOfChannel returns the NetworkMembers considered alive 86 // and also subscribed to the channel given 87 PeersOfChannel(common2.ChannelID) []discovery.NetworkMember 88 } 89 90 // MCSAdapter adapter of message crypto service interface to bound 91 // specific APIs required by state transfer service 92 type MCSAdapter interface { 93 // VerifyBlock returns nil if the block is properly signed, and the claimed seqNum is the 94 // sequence number that the block's header contains. 95 // else returns error 96 VerifyBlock(channelID common2.ChannelID, seqNum uint64, signedBlock *common.Block) error 97 98 // VerifyByChannel checks that signature is a valid signature of message 99 // under a peer's verification key, but also in the context of a specific channel. 100 // If the verification succeeded, Verify returns nil meaning no error occurred. 101 // If peerIdentity is nil, then the verification fails. 102 VerifyByChannel(channelID common2.ChannelID, peerIdentity api.PeerIdentityType, signature, message []byte) error 103 } 104 105 // ledgerResources defines abilities that the ledger provides 106 type ledgerResources interface { 107 // StoreBlock deliver new block with underlined private data 108 // returns missing transaction ids 109 StoreBlock(block *common.Block, data util.PvtDataCollections) error 110 111 // StorePvtData used to persist private date into transient store 112 StorePvtData(txid string, privData *transientstore.TxPvtReadWriteSetWithConfigInfo, blckHeight uint64) error 113 114 // GetPvtDataAndBlockByNum gets block by number and also returns all related private data 115 // that requesting peer is eligible for. 116 // The order of private data in slice of PvtDataCollections doesn't imply the order of 117 // transactions in the block related to these private data, to get the correct placement 118 // need to read TxPvtData.SeqInBlock field 119 GetPvtDataAndBlockByNum(seqNum uint64, peerAuthInfo protoutil.SignedData) (*common.Block, util.PvtDataCollections, error) 120 121 // Get recent block sequence number 122 LedgerHeight() (uint64, error) 123 124 // Close ledgerResources 125 Close() 126 } 127 128 // ServicesMediator aggregated adapter to compound all mediator 129 // required by state transfer into single struct 130 type ServicesMediator struct { 131 GossipAdapter 132 MCSAdapter 133 } 134 135 // GossipStateProviderImpl the implementation of the GossipStateProvider interface 136 // the struct to handle in memory sliding window of 137 // new ledger block to be acquired by hyper ledger 138 type GossipStateProviderImpl struct { 139 // Chain id 140 chainID string 141 142 mediator *ServicesMediator 143 144 // Queue of payloads which wasn't acquired yet 145 payloads PayloadsBuffer 146 147 ledger ledgerResources 148 149 stateResponseCh chan protoext.ReceivedMessage 150 151 stateRequestCh chan protoext.ReceivedMessage 152 153 stopCh chan struct{} 154 155 once sync.Once 156 157 stateTransferActive int32 158 159 stateMetrics *metrics.StateMetrics 160 161 requestValidator *stateRequestValidator 162 163 blockingMode bool 164 165 config *StateConfig 166 } 167 168 var logger = util.GetLogger(util.StateLogger, "") 169 170 // stateRequestValidator facilitates validation of the state request messages 171 type stateRequestValidator struct { 172 } 173 174 // validate checks for RemoteStateRequest message validity 175 func (v *stateRequestValidator) validate(request *proto.RemoteStateRequest, batchSize uint64) error { 176 if request.StartSeqNum > request.EndSeqNum { 177 return errors.Errorf("Invalid sequence interval [%d...%d).", request.StartSeqNum, request.EndSeqNum) 178 } 179 180 if request.EndSeqNum > batchSize+request.StartSeqNum { 181 return errors.Errorf("Requesting blocks range [%d-%d) greater than configured allowed"+ 182 " (%d) batching size for anti-entropy.", request.StartSeqNum, request.EndSeqNum, batchSize) 183 } 184 return nil 185 } 186 187 // NewGossipStateProvider creates state provider with coordinator instance 188 // to orchestrate arrival of private rwsets and blocks before committing them into the ledger. 189 func NewGossipStateProvider( 190 chainID string, 191 services *ServicesMediator, 192 ledger ledgerResources, 193 stateMetrics *metrics.StateMetrics, 194 blockingMode bool, 195 config *StateConfig, 196 ) GossipStateProvider { 197 198 gossipChan, _ := services.Accept(func(message interface{}) bool { 199 // Get only data messages 200 return protoext.IsDataMsg(message.(*proto.GossipMessage)) && 201 bytes.Equal(message.(*proto.GossipMessage).Channel, []byte(chainID)) 202 }, false) 203 204 remoteStateMsgFilter := func(message interface{}) bool { 205 receivedMsg := message.(protoext.ReceivedMessage) 206 msg := receivedMsg.GetGossipMessage() 207 if !(protoext.IsRemoteStateMessage(msg.GossipMessage) || msg.GetPrivateData() != nil) { 208 return false 209 } 210 // Ensure we deal only with messages that belong to this channel 211 if !bytes.Equal(msg.Channel, []byte(chainID)) { 212 return false 213 } 214 connInfo := receivedMsg.GetConnectionInfo() 215 authErr := services.VerifyByChannel(msg.Channel, connInfo.Identity, connInfo.Auth.Signature, connInfo.Auth.SignedData) 216 if authErr != nil { 217 logger.Warning("Got unauthorized request from", string(connInfo.Identity)) 218 return false 219 } 220 return true 221 } 222 223 // Filter message which are only relevant for nodeMetastate transfer 224 _, commChan := services.Accept(remoteStateMsgFilter, true) 225 226 height, err := ledger.LedgerHeight() 227 if height == 0 { 228 // Panic here since this is an indication of invalid situation which should not happen in normal 229 // code path. 230 logger.Panic("Committer height cannot be zero, ledger should include at least one block (genesis).") 231 } 232 233 if err != nil { 234 logger.Error("Could not read ledger info to obtain current ledger height due to: ", errors.WithStack(err)) 235 // Exiting as without ledger it will be impossible 236 // to deliver new blocks 237 return nil 238 } 239 240 s := &GossipStateProviderImpl{ 241 // MessageCryptoService 242 mediator: services, 243 // Chain ID 244 chainID: chainID, 245 // Create a queue for payloads, wrapped in a metrics buffer 246 payloads: &metricsBuffer{ 247 PayloadsBuffer: NewPayloadsBuffer(height), 248 sizeMetrics: stateMetrics.PayloadBufferSize, 249 chainID: chainID, 250 }, 251 ledger: ledger, 252 stateResponseCh: make(chan protoext.ReceivedMessage, config.StateChannelSize), 253 stateRequestCh: make(chan protoext.ReceivedMessage, config.StateChannelSize), 254 stopCh: make(chan struct{}), 255 stateTransferActive: 0, 256 once: sync.Once{}, 257 stateMetrics: stateMetrics, 258 requestValidator: &stateRequestValidator{}, 259 blockingMode: blockingMode, 260 config: config, 261 } 262 263 logger.Infof("Updating metadata information for channel %s, "+ 264 "current ledger sequence is at = %d, next expected block is = %d", chainID, height-1, s.payloads.Next()) 265 logger.Debug("Updating gossip ledger height to", height) 266 services.UpdateLedgerHeight(height, common2.ChannelID(s.chainID)) 267 268 // Listen for incoming communication 269 go s.receiveAndQueueGossipMessages(gossipChan) 270 go s.receiveAndDispatchDirectMessages(commChan) 271 // Deliver in order messages into the incoming channel 272 go s.deliverPayloads() 273 if s.config.StateEnabled { 274 // Execute anti entropy to fill missing gaps 275 go s.antiEntropy() 276 } 277 // Taking care of state request messages 278 go s.processStateRequests() 279 280 return s 281 } 282 283 func (s *GossipStateProviderImpl) receiveAndQueueGossipMessages(ch <-chan *proto.GossipMessage) { 284 for msg := range ch { 285 logger.Debug("Received new message via gossip channel") 286 go func(msg *proto.GossipMessage) { 287 if !bytes.Equal(msg.Channel, []byte(s.chainID)) { 288 logger.Warning("Received enqueue for channel", 289 string(msg.Channel), "while expecting channel", s.chainID, "ignoring enqueue") 290 return 291 } 292 293 dataMsg := msg.GetDataMsg() 294 if dataMsg != nil { 295 if err := s.addPayload(dataMsg.GetPayload(), nonBlocking); err != nil { 296 logger.Warningf("Block [%d] received from gossip wasn't added to payload buffer: %v", dataMsg.Payload.SeqNum, err) 297 return 298 } 299 300 } else { 301 logger.Debug("Gossip message received is not of data message type, usually this should not happen.") 302 } 303 }(msg) 304 } 305 } 306 307 func (s *GossipStateProviderImpl) receiveAndDispatchDirectMessages(ch <-chan protoext.ReceivedMessage) { 308 for msg := range ch { 309 logger.Debug("Dispatching a message", msg) 310 go func(msg protoext.ReceivedMessage) { 311 gm := msg.GetGossipMessage() 312 // Check type of the message 313 if protoext.IsRemoteStateMessage(gm.GossipMessage) { 314 logger.Debug("Handling direct state transfer message") 315 // Got state transfer request response 316 s.directMessage(msg) 317 } else if gm.GetPrivateData() != nil { 318 logger.Debug("Handling private data collection message") 319 // Handling private data replication message 320 s.privateDataMessage(msg) 321 } 322 }(msg) 323 } 324 } 325 326 func (s *GossipStateProviderImpl) privateDataMessage(msg protoext.ReceivedMessage) { 327 if !bytes.Equal(msg.GetGossipMessage().Channel, []byte(s.chainID)) { 328 logger.Warning("Received state transfer request for channel", 329 string(msg.GetGossipMessage().Channel), "while expecting channel", s.chainID, "skipping request...") 330 return 331 } 332 333 gossipMsg := msg.GetGossipMessage() 334 pvtDataMsg := gossipMsg.GetPrivateData() 335 336 if pvtDataMsg.Payload == nil { 337 logger.Warning("Malformed private data message, no payload provided") 338 return 339 } 340 341 collectionName := pvtDataMsg.Payload.CollectionName 342 txID := pvtDataMsg.Payload.TxId 343 pvtRwSet := pvtDataMsg.Payload.PrivateRwset 344 345 if len(pvtRwSet) == 0 { 346 logger.Warning("Malformed private data message, no rwset provided, collection name = ", collectionName) 347 return 348 } 349 350 txPvtRwSet := &rwset.TxPvtReadWriteSet{ 351 DataModel: rwset.TxReadWriteSet_KV, 352 NsPvtRwset: []*rwset.NsPvtReadWriteSet{{ 353 Namespace: pvtDataMsg.Payload.Namespace, 354 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{{ 355 CollectionName: collectionName, 356 Rwset: pvtRwSet, 357 }}}, 358 }, 359 } 360 361 txPvtRwSetWithConfig := &transientstore.TxPvtReadWriteSetWithConfigInfo{ 362 PvtRwset: txPvtRwSet, 363 CollectionConfigs: map[string]*peer.CollectionConfigPackage{ 364 pvtDataMsg.Payload.Namespace: pvtDataMsg.Payload.CollectionConfigs, 365 }, 366 } 367 368 if err := s.ledger.StorePvtData(txID, txPvtRwSetWithConfig, pvtDataMsg.Payload.PrivateSimHeight); err != nil { 369 logger.Errorf("Wasn't able to persist private data for collection %s, due to %s", collectionName, err) 370 msg.Ack(err) // Sending NACK to indicate failure of storing collection 371 } 372 373 msg.Ack(nil) 374 logger.Debug("Private data for collection", collectionName, "has been stored") 375 } 376 377 func (s *GossipStateProviderImpl) directMessage(msg protoext.ReceivedMessage) { 378 logger.Debug("[ENTER] -> directMessage") 379 defer logger.Debug("[EXIT] -> directMessage") 380 381 if msg == nil { 382 logger.Error("Got nil message via end-to-end channel, should not happen!") 383 return 384 } 385 386 if !bytes.Equal(msg.GetGossipMessage().Channel, []byte(s.chainID)) { 387 logger.Warning("Received state transfer request for channel", 388 string(msg.GetGossipMessage().Channel), "while expecting channel", s.chainID, "skipping request...") 389 return 390 } 391 392 incoming := msg.GetGossipMessage() 393 394 if incoming.GetStateRequest() != nil { 395 if len(s.stateRequestCh) < s.config.StateChannelSize { 396 // Forward state request to the channel, if there are too 397 // many message of state request ignore to avoid flooding. 398 s.stateRequestCh <- msg 399 } 400 } else if incoming.GetStateResponse() != nil { 401 // If no state transfer procedure activate there is 402 // no reason to process the message 403 if atomic.LoadInt32(&s.stateTransferActive) == 1 { 404 // Send signal of state response message 405 s.stateResponseCh <- msg 406 } 407 } 408 } 409 410 func (s *GossipStateProviderImpl) processStateRequests() { 411 for { 412 msg, stillOpen := <-s.stateRequestCh 413 if !stillOpen { 414 return 415 } 416 s.handleStateRequest(msg) 417 } 418 } 419 420 // handleStateRequest handles state request message, validate batch size, reads current leader state to 421 // obtain required blocks, builds response message and send it back 422 func (s *GossipStateProviderImpl) handleStateRequest(msg protoext.ReceivedMessage) { 423 if msg == nil { 424 return 425 } 426 request := msg.GetGossipMessage().GetStateRequest() 427 428 if err := s.requestValidator.validate(request, s.config.StateBatchSize); err != nil { 429 logger.Errorf("State request validation failed, %s. Ignoring request...", err) 430 return 431 } 432 433 currentHeight, err := s.ledger.LedgerHeight() 434 if err != nil { 435 logger.Errorf("Cannot access to current ledger height, due to %+v", err) 436 return 437 } 438 if currentHeight < request.EndSeqNum { 439 logger.Warningf("Received state request to transfer blocks with sequence numbers higher [%d...%d] "+ 440 "than available in ledger (%d)", request.StartSeqNum, request.StartSeqNum, currentHeight) 441 } 442 443 endSeqNum := min(currentHeight, request.EndSeqNum) 444 445 response := &proto.RemoteStateResponse{Payloads: make([]*proto.Payload, 0)} 446 for seqNum := request.StartSeqNum; seqNum <= endSeqNum; seqNum++ { 447 logger.Debug("Reading block ", seqNum, " with private data from the coordinator service") 448 connInfo := msg.GetConnectionInfo() 449 peerAuthInfo := protoutil.SignedData{ 450 Data: connInfo.Auth.SignedData, 451 Signature: connInfo.Auth.Signature, 452 Identity: connInfo.Identity, 453 } 454 block, pvtData, err := s.ledger.GetPvtDataAndBlockByNum(seqNum, peerAuthInfo) 455 456 if err != nil { 457 logger.Errorf("cannot read block number %d from ledger, because %+v, skipping...", seqNum, err) 458 continue 459 } 460 461 if block == nil { 462 logger.Errorf("Wasn't able to read block with sequence number %d from ledger, skipping....", seqNum) 463 continue 464 } 465 466 blockBytes, err := pb.Marshal(block) 467 468 if err != nil { 469 logger.Errorf("Could not marshal block: %+v", errors.WithStack(err)) 470 continue 471 } 472 473 var pvtBytes [][]byte 474 if pvtData != nil { 475 // Marshal private data 476 pvtBytes, err = pvtData.Marshal() 477 if err != nil { 478 logger.Errorf("Failed to marshal private rwset for block %d due to %+v", seqNum, errors.WithStack(err)) 479 continue 480 } 481 } 482 483 // Appending result to the response 484 response.Payloads = append(response.Payloads, &proto.Payload{ 485 SeqNum: seqNum, 486 Data: blockBytes, 487 PrivateData: pvtBytes, 488 }) 489 } 490 // Sending back response with missing blocks 491 msg.Respond(&proto.GossipMessage{ 492 // Copy nonce field from the request, so it will be possible to match response 493 Nonce: msg.GetGossipMessage().Nonce, 494 Tag: proto.GossipMessage_CHAN_OR_ORG, 495 Channel: []byte(s.chainID), 496 Content: &proto.GossipMessage_StateResponse{StateResponse: response}, 497 }) 498 } 499 500 func (s *GossipStateProviderImpl) handleStateResponse(msg protoext.ReceivedMessage) (uint64, error) { 501 max := uint64(0) 502 // Send signal that response for given nonce has been received 503 response := msg.GetGossipMessage().GetStateResponse() 504 // Extract payloads, verify and push into buffer 505 if len(response.GetPayloads()) == 0 { 506 return uint64(0), errors.New("Received state transfer response without payload") 507 } 508 for _, payload := range response.GetPayloads() { 509 logger.Debugf("Received payload with sequence number %d.", payload.SeqNum) 510 block, err := protoutil.UnmarshalBlock(payload.Data) 511 if err != nil { 512 logger.Warningf("Error unmarshaling payload to block for sequence number %d, due to %+v", payload.SeqNum, err) 513 return uint64(0), err 514 } 515 516 if err := s.mediator.VerifyBlock(common2.ChannelID(s.chainID), payload.SeqNum, block); err != nil { 517 err = errors.WithStack(err) 518 logger.Warningf("Error verifying block with sequence number %d, due to %+v", payload.SeqNum, err) 519 return uint64(0), err 520 } 521 if max < payload.SeqNum { 522 max = payload.SeqNum 523 } 524 525 err = s.addPayload(payload, blocking) 526 if err != nil { 527 logger.Warningf("Block [%d] received from block transfer wasn't added to payload buffer: %v", payload.SeqNum, err) 528 } 529 } 530 return max, nil 531 } 532 533 // Stop function sends halting signal to all go routines 534 func (s *GossipStateProviderImpl) Stop() { 535 // Make sure stop won't be executed twice 536 // and stop channel won't be used again 537 s.once.Do(func() { 538 close(s.stopCh) 539 // Close all resources 540 s.ledger.Close() 541 close(s.stateRequestCh) 542 close(s.stateResponseCh) 543 }) 544 } 545 546 func (s *GossipStateProviderImpl) deliverPayloads() { 547 for { 548 select { 549 // Wait for notification that next seq has arrived 550 case <-s.payloads.Ready(): 551 logger.Debugf("[%s] Ready to transfer payloads (blocks) to the ledger, next block number is = [%d]", s.chainID, s.payloads.Next()) 552 // Collect all subsequent payloads 553 for payload := s.payloads.Pop(); payload != nil; payload = s.payloads.Pop() { 554 rawBlock := &common.Block{} 555 if err := pb.Unmarshal(payload.Data, rawBlock); err != nil { 556 logger.Errorf("Error getting block with seqNum = %d due to (%+v)...dropping block", payload.SeqNum, errors.WithStack(err)) 557 continue 558 } 559 if rawBlock.Data == nil || rawBlock.Header == nil { 560 logger.Errorf("Block with claimed sequence %d has no header (%v) or data (%v)", 561 payload.SeqNum, rawBlock.Header, rawBlock.Data) 562 continue 563 } 564 logger.Debugf("[%s] Transferring block [%d] with %d transaction(s) to the ledger", s.chainID, payload.SeqNum, len(rawBlock.Data.Data)) 565 566 // Read all private data into slice 567 var p util.PvtDataCollections 568 if payload.PrivateData != nil { 569 err := p.Unmarshal(payload.PrivateData) 570 if err != nil { 571 logger.Errorf("Wasn't able to unmarshal private data for block seqNum = %d due to (%+v)...dropping block", payload.SeqNum, errors.WithStack(err)) 572 continue 573 } 574 } 575 if err := s.commitBlock(rawBlock, p); err != nil { 576 if executionErr, isExecutionErr := err.(*vsccErrors.VSCCExecutionFailureError); isExecutionErr { 577 logger.Errorf("Failed executing VSCC due to %v. Aborting chain processing", executionErr) 578 return 579 } 580 logger.Panicf("Cannot commit block to the ledger due to %+v", errors.WithStack(err)) 581 } 582 } 583 case <-s.stopCh: 584 logger.Debug("State provider has been stopped, finishing to push new blocks.") 585 return 586 } 587 } 588 } 589 590 func (s *GossipStateProviderImpl) antiEntropy() { 591 defer logger.Debug("State Provider stopped, stopping anti entropy procedure.") 592 593 for { 594 select { 595 case <-s.stopCh: 596 return 597 case <-time.After(s.config.StateCheckInterval): 598 ourHeight, err := s.ledger.LedgerHeight() 599 if err != nil { 600 // Unable to read from ledger continue to the next round 601 logger.Errorf("Cannot obtain ledger height, due to %+v", errors.WithStack(err)) 602 continue 603 } 604 if ourHeight == 0 { 605 logger.Error("Ledger reported block height of 0 but this should be impossible") 606 continue 607 } 608 maxHeight := s.maxAvailableLedgerHeight() 609 if ourHeight >= maxHeight { 610 continue 611 } 612 613 s.requestBlocksInRange(uint64(ourHeight), uint64(maxHeight)-1) 614 } 615 } 616 } 617 618 // maxAvailableLedgerHeight iterates over all available peers and checks advertised meta state to 619 // find maximum available ledger height across peers 620 func (s *GossipStateProviderImpl) maxAvailableLedgerHeight() uint64 { 621 max := uint64(0) 622 for _, p := range s.mediator.PeersOfChannel(common2.ChannelID(s.chainID)) { 623 if p.Properties == nil { 624 logger.Debug("Peer", p.PreferredEndpoint(), "doesn't have properties, skipping it") 625 continue 626 } 627 peerHeight := p.Properties.LedgerHeight 628 if max < peerHeight { 629 max = peerHeight 630 } 631 } 632 return max 633 } 634 635 // requestBlocksInRange capable to acquire blocks with sequence 636 // numbers in the range [start...end). 637 func (s *GossipStateProviderImpl) requestBlocksInRange(start uint64, end uint64) { 638 atomic.StoreInt32(&s.stateTransferActive, 1) 639 defer atomic.StoreInt32(&s.stateTransferActive, 0) 640 641 for prev := start; prev <= end; { 642 next := min(end, prev+s.config.StateBatchSize) 643 644 gossipMsg := s.stateRequestMessage(prev, next) 645 646 responseReceived := false 647 tryCounts := 0 648 649 for !responseReceived { 650 if tryCounts > s.config.StateMaxRetries { 651 logger.Warningf("Wasn't able to get blocks in range [%d...%d), after %d retries", 652 prev, next, tryCounts) 653 return 654 } 655 // Select peers to ask for blocks 656 peer, err := s.selectPeerToRequestFrom(next) 657 if err != nil { 658 logger.Warningf("Cannot send state request for blocks in range [%d...%d), due to %+v", 659 prev, next, errors.WithStack(err)) 660 return 661 } 662 663 logger.Debugf("State transfer, with peer %s, requesting blocks in range [%d...%d), "+ 664 "for chainID %s", peer.Endpoint, prev, next, s.chainID) 665 666 s.mediator.Send(gossipMsg, peer) 667 tryCounts++ 668 669 // Wait until timeout or response arrival 670 select { 671 case msg, stillOpen := <-s.stateResponseCh: 672 if !stillOpen { 673 return 674 } 675 if msg.GetGossipMessage().Nonce != 676 gossipMsg.Nonce { 677 continue 678 } 679 // Got corresponding response for state request, can continue 680 index, err := s.handleStateResponse(msg) 681 if err != nil { 682 logger.Warningf("Wasn't able to process state response for "+ 683 "blocks [%d...%d], due to %+v", prev, next, errors.WithStack(err)) 684 continue 685 } 686 prev = index + 1 687 responseReceived = true 688 case <-time.After(s.config.StateResponseTimeout): 689 } 690 } 691 } 692 } 693 694 // stateRequestMessage generates state request message for given blocks in range [beginSeq...endSeq] 695 func (s *GossipStateProviderImpl) stateRequestMessage(beginSeq uint64, endSeq uint64) *proto.GossipMessage { 696 return &proto.GossipMessage{ 697 Nonce: util.RandomUInt64(), 698 Tag: proto.GossipMessage_CHAN_OR_ORG, 699 Channel: []byte(s.chainID), 700 Content: &proto.GossipMessage_StateRequest{ 701 StateRequest: &proto.RemoteStateRequest{ 702 StartSeqNum: beginSeq, 703 EndSeqNum: endSeq, 704 }, 705 }, 706 } 707 } 708 709 // selectPeerToRequestFrom selects peer which has required blocks to ask missing blocks from 710 func (s *GossipStateProviderImpl) selectPeerToRequestFrom(height uint64) (*comm.RemotePeer, error) { 711 // Filter peers which posses required range of missing blocks 712 peers := s.filterPeers(s.hasRequiredHeight(height)) 713 714 n := len(peers) 715 if n == 0 { 716 return nil, errors.New("there are no peers to ask for missing blocks from") 717 } 718 719 // Select peer to ask for blocks 720 return peers[util.RandomInt(n)], nil 721 } 722 723 // filterPeers returns list of peers which aligns the predicate provided 724 func (s *GossipStateProviderImpl) filterPeers(predicate func(peer discovery.NetworkMember) bool) []*comm.RemotePeer { 725 var peers []*comm.RemotePeer 726 727 for _, member := range s.mediator.PeersOfChannel(common2.ChannelID(s.chainID)) { 728 if predicate(member) { 729 peers = append(peers, &comm.RemotePeer{Endpoint: member.PreferredEndpoint(), PKIID: member.PKIid}) 730 } 731 } 732 733 return peers 734 } 735 736 // hasRequiredHeight returns predicate which is capable to filter peers with ledger height above than indicated 737 // by provided input parameter 738 func (s *GossipStateProviderImpl) hasRequiredHeight(height uint64) func(peer discovery.NetworkMember) bool { 739 return func(peer discovery.NetworkMember) bool { 740 if peer.Properties != nil { 741 return peer.Properties.LedgerHeight >= height 742 } 743 logger.Debug(peer.PreferredEndpoint(), "doesn't have properties") 744 return false 745 } 746 } 747 748 // AddPayload adds new payload into state. 749 func (s *GossipStateProviderImpl) AddPayload(payload *proto.Payload) error { 750 return s.addPayload(payload, s.blockingMode) 751 } 752 753 // addPayload adds new payload into state. It may (or may not) block according to the 754 // given parameter. If it gets a block while in blocking mode - it would wait until 755 // the block is sent into the payloads buffer. 756 // Else - it may drop the block, if the payload buffer is too full. 757 func (s *GossipStateProviderImpl) addPayload(payload *proto.Payload, blockingMode bool) error { 758 if payload == nil { 759 return errors.New("Given payload is nil") 760 } 761 logger.Debugf("[%s] Adding payload to local buffer, blockNum = [%d]", s.chainID, payload.SeqNum) 762 height, err := s.ledger.LedgerHeight() 763 if err != nil { 764 return errors.Wrap(err, "Failed obtaining ledger height") 765 } 766 767 if !blockingMode && payload.SeqNum-height >= uint64(s.config.StateBlockBufferSize) { 768 return errors.Errorf("Ledger height is at %d, cannot enqueue block with sequence of %d", height, payload.SeqNum) 769 } 770 771 for blockingMode && s.payloads.Size() > s.config.StateBlockBufferSize*2 { 772 time.Sleep(enqueueRetryInterval) 773 } 774 775 s.payloads.Push(payload) 776 logger.Debugf("Blocks payloads buffer size for channel [%s] is %d blocks", s.chainID, s.payloads.Size()) 777 return nil 778 } 779 780 func (s *GossipStateProviderImpl) commitBlock(block *common.Block, pvtData util.PvtDataCollections) error { 781 782 t1 := time.Now() 783 784 // Commit block with available private transactions 785 if err := s.ledger.StoreBlock(block, pvtData); err != nil { 786 logger.Errorf("Got error while committing(%+v)", errors.WithStack(err)) 787 return err 788 } 789 790 sinceT1 := time.Since(t1) 791 s.stateMetrics.CommitDuration.With("channel", s.chainID).Observe(sinceT1.Seconds()) 792 793 // Update ledger height 794 s.mediator.UpdateLedgerHeight(block.Header.Number+1, common2.ChannelID(s.chainID)) 795 logger.Debugf("[%s] Committed block [%d] with %d transaction(s)", 796 s.chainID, block.Header.Number, len(block.Data.Data)) 797 798 s.stateMetrics.Height.With("channel", s.chainID).Set(float64(block.Header.Number + 1)) 799 800 return nil 801 } 802 803 func min(a uint64, b uint64) uint64 { 804 return b ^ ((a ^ b) & (-(uint64(a-b) >> 63))) 805 }