github.com/kaituanwang/hyperledger@v2.0.1+incompatible/orderer/common/cluster/replication.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package cluster 8 9 import ( 10 "bytes" 11 "encoding/base64" 12 "encoding/hex" 13 "encoding/pem" 14 "time" 15 16 "github.com/hyperledger/fabric-protos-go/common" 17 "github.com/hyperledger/fabric/bccsp" 18 "github.com/hyperledger/fabric/common/flogging" 19 "github.com/hyperledger/fabric/core/comm" 20 "github.com/hyperledger/fabric/internal/pkg/identity" 21 "github.com/hyperledger/fabric/orderer/common/localconfig" 22 "github.com/hyperledger/fabric/protoutil" 23 "github.com/pkg/errors" 24 ) 25 26 const ( 27 // RetryTimeout is the time the block puller retries. 28 RetryTimeout = time.Second * 10 29 ) 30 31 // ChannelPredicate accepts channels according to their names. 32 type ChannelPredicate func(channelName string) bool 33 34 // AnyChannel accepts all channels. 35 func AnyChannel(_ string) bool { 36 return true 37 } 38 39 // PullerConfigFromTopLevelConfig creates a PullerConfig from a TopLevel config, 40 // and from a signer and TLS key cert pair. 41 // The PullerConfig's channel is initialized to be the system channel. 42 func PullerConfigFromTopLevelConfig( 43 systemChannel string, 44 conf *localconfig.TopLevel, 45 tlsKey, 46 tlsCert []byte, 47 signer identity.SignerSerializer, 48 ) PullerConfig { 49 return PullerConfig{ 50 Channel: systemChannel, 51 MaxTotalBufferBytes: conf.General.Cluster.ReplicationBufferSize, 52 Timeout: conf.General.Cluster.RPCTimeout, 53 TLSKey: tlsKey, 54 TLSCert: tlsCert, 55 Signer: signer, 56 } 57 } 58 59 //go:generate mockery -dir . -name LedgerWriter -case underscore -output mocks/ 60 61 // LedgerWriter allows the caller to write blocks and inspect the height 62 type LedgerWriter interface { 63 // Append a new block to the ledger 64 Append(block *common.Block) error 65 66 // Height returns the number of blocks on the ledger 67 Height() uint64 68 } 69 70 //go:generate mockery -dir . -name LedgerFactory -case underscore -output mocks/ 71 72 // LedgerFactory retrieves or creates new ledgers by chainID 73 type LedgerFactory interface { 74 // GetOrCreate gets an existing ledger (if it exists) 75 // or creates it if it does not 76 GetOrCreate(chainID string) (LedgerWriter, error) 77 } 78 79 //go:generate mockery -dir . -name ChannelLister -case underscore -output mocks/ 80 81 // ChannelLister returns a list of channels 82 type ChannelLister interface { 83 // Channels returns a list of channels 84 Channels() []ChannelGenesisBlock 85 // Close closes the ChannelLister 86 Close() 87 } 88 89 // Replicator replicates chains 90 type Replicator struct { 91 DoNotPanicIfClusterNotReachable bool 92 Filter ChannelPredicate 93 SystemChannel string 94 ChannelLister ChannelLister 95 Logger *flogging.FabricLogger 96 Puller *BlockPuller 97 BootBlock *common.Block 98 AmIPartOfChannel SelfMembershipPredicate 99 LedgerFactory LedgerFactory 100 } 101 102 // IsReplicationNeeded returns whether replication is needed, 103 // or the cluster node can resume standard boot flow. 104 func (r *Replicator) IsReplicationNeeded() (bool, error) { 105 systemChannelLedger, err := r.LedgerFactory.GetOrCreate(r.SystemChannel) 106 if err != nil { 107 return false, err 108 } 109 110 height := systemChannelLedger.Height() 111 var lastBlockSeq uint64 112 // If Height is 0 then lastBlockSeq would be 2^64 - 1, 113 // so make it 0 to take care of the overflow. 114 if height == 0 { 115 lastBlockSeq = 0 116 } else { 117 lastBlockSeq = height - 1 118 } 119 120 if r.BootBlock.Header.Number > lastBlockSeq { 121 return true, nil 122 } 123 return false, nil 124 } 125 126 // ReplicateChains pulls chains and commits them. 127 // Returns the names of the chains replicated successfully. 128 func (r *Replicator) ReplicateChains() []string { 129 var replicatedChains []string 130 channels := r.discoverChannels() 131 pullHints := r.channelsToPull(channels) 132 totalChannelCount := len(pullHints.channelsToPull) + len(pullHints.channelsNotToPull) 133 r.Logger.Info("Found myself in", len(pullHints.channelsToPull), "channels out of", totalChannelCount, ":", pullHints) 134 135 // Append the genesis blocks of the application channels we have into the ledger 136 for _, channels := range [][]ChannelGenesisBlock{pullHints.channelsToPull, pullHints.channelsNotToPull} { 137 for _, channel := range channels { 138 ledger, err := r.LedgerFactory.GetOrCreate(channel.ChannelName) 139 if err != nil { 140 r.Logger.Panicf("Failed to create a ledger for channel %s: %v", channel.ChannelName, err) 141 } 142 143 if channel.GenesisBlock == nil { 144 if ledger.Height() == 0 { 145 r.Logger.Panicf("Expecting channel %s to at least contain genesis block, but it doesn't", channel.ChannelName) 146 } 147 148 continue 149 } 150 151 r.appendBlock(channel.GenesisBlock, ledger, channel.ChannelName) 152 } 153 } 154 155 for _, channel := range pullHints.channelsToPull { 156 err := r.PullChannel(channel.ChannelName) 157 if err == nil { 158 replicatedChains = append(replicatedChains, channel.ChannelName) 159 } else { 160 r.Logger.Warningf("Failed pulling channel %s: %v", channel.ChannelName, err) 161 } 162 } 163 164 // Last, pull the system chain. 165 if err := r.PullChannel(r.SystemChannel); err != nil && err != ErrSkipped { 166 r.Logger.Panicf("Failed pulling system channel: %v", err) 167 } 168 return replicatedChains 169 } 170 171 func (r *Replicator) discoverChannels() []ChannelGenesisBlock { 172 r.Logger.Debug("Entering") 173 defer r.Logger.Debug("Exiting") 174 channels := GenesisBlocks(r.ChannelLister.Channels()) 175 r.Logger.Info("Discovered", len(channels), "channels:", channels.Names()) 176 r.ChannelLister.Close() 177 return channels 178 } 179 180 // PullChannel pulls the given channel from some orderer, 181 // and commits it to the ledger. 182 func (r *Replicator) PullChannel(channel string) error { 183 if !r.Filter(channel) { 184 r.Logger.Infof("Channel %s shouldn't be pulled. Skipping it", channel) 185 return ErrSkipped 186 } 187 r.Logger.Info("Pulling channel", channel) 188 puller := r.Puller.Clone() 189 defer puller.Close() 190 puller.Channel = channel 191 192 ledger, err := r.LedgerFactory.GetOrCreate(channel) 193 if err != nil { 194 r.Logger.Panicf("Failed to create a ledger for channel %s: %v", channel, err) 195 } 196 197 endpoint, latestHeight, _ := latestHeightAndEndpoint(puller) 198 if endpoint == "" { 199 return errors.Errorf("failed obtaining the latest block for channel %s", channel) 200 } 201 r.Logger.Info("Latest block height for channel", channel, "is", latestHeight) 202 // Ensure that if we pull the system channel, the latestHeight is bigger or equal to the 203 // bootstrap block of the system channel. 204 // Otherwise, we'd be left with a block gap. 205 if channel == r.SystemChannel && latestHeight-1 < r.BootBlock.Header.Number { 206 return errors.Errorf("latest height found among system channel(%s) orderers is %d, but the boot block's "+ 207 "sequence is %d", r.SystemChannel, latestHeight, r.BootBlock.Header.Number) 208 } 209 return r.pullChannelBlocks(channel, puller, latestHeight, ledger) 210 } 211 212 func (r *Replicator) pullChannelBlocks(channel string, puller *BlockPuller, latestHeight uint64, ledger LedgerWriter) error { 213 nextBlockToPull := ledger.Height() 214 if nextBlockToPull == latestHeight { 215 r.Logger.Infof("Latest height found (%d) is equal to our height, skipping pulling channel %s", latestHeight, channel) 216 return nil 217 } 218 // Pull the next block and remember its hash. 219 nextBlock := puller.PullBlock(nextBlockToPull) 220 if nextBlock == nil { 221 return ErrRetryCountExhausted 222 } 223 r.appendBlock(nextBlock, ledger, channel) 224 actualPrevHash := protoutil.BlockHeaderHash(nextBlock.Header) 225 226 for seq := uint64(nextBlockToPull + 1); seq < latestHeight; seq++ { 227 block := puller.PullBlock(seq) 228 if block == nil { 229 return ErrRetryCountExhausted 230 } 231 reportedPrevHash := block.Header.PreviousHash 232 if !bytes.Equal(reportedPrevHash, actualPrevHash) { 233 return errors.Errorf("block header mismatch on sequence %d, expected %x, got %x", 234 block.Header.Number, actualPrevHash, reportedPrevHash) 235 } 236 actualPrevHash = protoutil.BlockHeaderHash(block.Header) 237 if channel == r.SystemChannel && block.Header.Number == r.BootBlock.Header.Number { 238 r.compareBootBlockWithSystemChannelLastConfigBlock(block) 239 r.appendBlock(block, ledger, channel) 240 // No need to pull further blocks from the system channel 241 return nil 242 } 243 r.appendBlock(block, ledger, channel) 244 } 245 return nil 246 } 247 248 func (r *Replicator) appendBlock(block *common.Block, ledger LedgerWriter, channel string) { 249 height := ledger.Height() 250 if height > block.Header.Number { 251 r.Logger.Infof("Skipping commit of block [%d] for channel %s because height is at %d", block.Header.Number, channel, height) 252 return 253 } 254 if err := ledger.Append(block); err != nil { 255 r.Logger.Panicf("Failed to write block [%d]: %v", block.Header.Number, err) 256 } 257 r.Logger.Infof("Committed block [%d] for channel %s", block.Header.Number, channel) 258 } 259 260 func (r *Replicator) compareBootBlockWithSystemChannelLastConfigBlock(block *common.Block) { 261 // Overwrite the received block's data hash 262 block.Header.DataHash = protoutil.BlockDataHash(block.Data) 263 264 bootBlockHash := protoutil.BlockHeaderHash(r.BootBlock.Header) 265 retrievedBlockHash := protoutil.BlockHeaderHash(block.Header) 266 if bytes.Equal(bootBlockHash, retrievedBlockHash) { 267 return 268 } 269 r.Logger.Panicf("Block header mismatch on last system channel block, expected %s, got %s", 270 hex.EncodeToString(bootBlockHash), hex.EncodeToString(retrievedBlockHash)) 271 } 272 273 type channelPullHints struct { 274 channelsToPull []ChannelGenesisBlock 275 channelsNotToPull []ChannelGenesisBlock 276 } 277 278 func (r *Replicator) channelsToPull(channels GenesisBlocks) channelPullHints { 279 r.Logger.Info("Evaluating channels to pull:", channels.Names()) 280 281 // Backup the verifier of the puller 282 verifier := r.Puller.VerifyBlockSequence 283 // Restore it at the end of the function 284 defer func() { 285 r.Puller.VerifyBlockSequence = verifier 286 }() 287 // Set it to be a no-op verifier, because we can't verify latest blocks of channels. 288 r.Puller.VerifyBlockSequence = func(blocks []*common.Block, channel string) error { 289 return nil 290 } 291 292 var channelsNotToPull []ChannelGenesisBlock 293 var channelsToPull []ChannelGenesisBlock 294 for _, channel := range channels { 295 r.Logger.Info("Probing whether I should pull channel", channel.ChannelName) 296 puller := r.Puller.Clone() 297 puller.Channel = channel.ChannelName 298 // Disable puller buffering when we check whether we are in the channel, 299 // as we only need to know about a single block. 300 bufferSize := puller.MaxTotalBufferBytes 301 puller.MaxTotalBufferBytes = 1 302 err := Participant(puller, r.AmIPartOfChannel) 303 puller.Close() 304 // Restore the previous buffer size 305 puller.MaxTotalBufferBytes = bufferSize 306 if err == ErrNotInChannel || err == ErrForbidden { 307 r.Logger.Infof("I do not belong to channel %s or am forbidden pulling it (%v), skipping chain retrieval", channel.ChannelName, err) 308 channelsNotToPull = append(channelsNotToPull, channel) 309 continue 310 } 311 if err == ErrServiceUnavailable { 312 r.Logger.Infof("All orderers in the system channel are either down,"+ 313 "or do not service channel %s (%v), skipping chain retrieval", channel.ChannelName, err) 314 channelsNotToPull = append(channelsNotToPull, channel) 315 continue 316 } 317 if err == ErrRetryCountExhausted { 318 r.Logger.Warningf("Could not obtain blocks needed for classifying whether I am in the channel,"+ 319 "skipping the retrieval of the chan %s", channel.ChannelName) 320 channelsNotToPull = append(channelsNotToPull, channel) 321 continue 322 } 323 if err != nil { 324 if !r.DoNotPanicIfClusterNotReachable { 325 r.Logger.Panicf("Failed classifying whether I belong to channel %s: %v, skipping chain retrieval", channel.ChannelName, err) 326 } 327 continue 328 } 329 r.Logger.Infof("I need to pull channel %s", channel.ChannelName) 330 channelsToPull = append(channelsToPull, channel) 331 } 332 return channelPullHints{ 333 channelsToPull: channelsToPull, 334 channelsNotToPull: channelsNotToPull, 335 } 336 } 337 338 // PullerConfig configures a BlockPuller. 339 type PullerConfig struct { 340 TLSKey []byte 341 TLSCert []byte 342 Timeout time.Duration 343 Signer identity.SignerSerializer 344 Channel string 345 MaxTotalBufferBytes int 346 } 347 348 //go:generate mockery -dir . -name VerifierRetriever -case underscore -output mocks/ 349 350 // VerifierRetriever retrieves BlockVerifiers for channels. 351 type VerifierRetriever interface { 352 // RetrieveVerifier retrieves a BlockVerifier for the given channel. 353 RetrieveVerifier(channel string) BlockVerifier 354 } 355 356 // BlockPullerFromConfigBlock returns a BlockPuller that doesn't verify signatures on blocks. 357 func BlockPullerFromConfigBlock(conf PullerConfig, block *common.Block, verifierRetriever VerifierRetriever, bccsp bccsp.BCCSP) (*BlockPuller, error) { 358 if block == nil { 359 return nil, errors.New("nil block") 360 } 361 362 endpoints, err := EndpointconfigFromConfigBlock(block, bccsp) 363 if err != nil { 364 return nil, err 365 } 366 367 clientConf := comm.ClientConfig{ 368 Timeout: conf.Timeout, 369 SecOpts: comm.SecureOptions{ 370 Certificate: conf.TLSCert, 371 Key: conf.TLSKey, 372 RequireClientCert: true, 373 UseTLS: true, 374 }, 375 } 376 377 dialer := &StandardDialer{ 378 Config: clientConf.Clone(), 379 } 380 381 tlsCertAsDER, _ := pem.Decode(conf.TLSCert) 382 if tlsCertAsDER == nil { 383 return nil, errors.Errorf("unable to decode TLS certificate PEM: %s", base64.StdEncoding.EncodeToString(conf.TLSCert)) 384 } 385 386 return &BlockPuller{ 387 Logger: flogging.MustGetLogger("orderer.common.cluster.replication").With("channel", conf.Channel), 388 Dialer: dialer, 389 TLSCert: tlsCertAsDER.Bytes, 390 VerifyBlockSequence: func(blocks []*common.Block, channel string) error { 391 verifier := verifierRetriever.RetrieveVerifier(channel) 392 if verifier == nil { 393 return errors.Errorf("couldn't acquire verifier for channel %s", channel) 394 } 395 return VerifyBlocks(blocks, verifier) 396 }, 397 MaxTotalBufferBytes: conf.MaxTotalBufferBytes, 398 Endpoints: endpoints, 399 RetryTimeout: RetryTimeout, 400 FetchTimeout: conf.Timeout, 401 Channel: conf.Channel, 402 Signer: conf.Signer, 403 }, nil 404 } 405 406 // NoopBlockVerifier doesn't verify block signatures 407 type NoopBlockVerifier struct{} 408 409 // VerifyBlockSignature accepts all signatures over blocks. 410 func (*NoopBlockVerifier) VerifyBlockSignature(sd []*protoutil.SignedData, config *common.ConfigEnvelope) error { 411 return nil 412 } 413 414 //go:generate mockery -dir . -name ChainPuller -case underscore -output mocks/ 415 416 // ChainPuller pulls blocks from a chain 417 type ChainPuller interface { 418 // PullBlock pulls the given block from some orderer node 419 PullBlock(seq uint64) *common.Block 420 421 // HeightsByEndpoints returns the block heights by endpoints of orderers 422 HeightsByEndpoints() (map[string]uint64, error) 423 424 // Close closes the ChainPuller 425 Close() 426 } 427 428 // ChainInspector walks over a chain 429 type ChainInspector struct { 430 Logger *flogging.FabricLogger 431 Puller ChainPuller 432 LastConfigBlock *common.Block 433 } 434 435 // ErrSkipped denotes that replicating a chain was skipped 436 var ErrSkipped = errors.New("skipped") 437 438 // ErrForbidden denotes that an ordering node refuses sending blocks due to access control. 439 var ErrForbidden = errors.New("forbidden pulling the channel") 440 441 // ErrServiceUnavailable denotes that an ordering node is not servicing at the moment. 442 var ErrServiceUnavailable = errors.New("service unavailable") 443 444 // ErrNotInChannel denotes that an ordering node is not in the channel 445 var ErrNotInChannel = errors.New("not in the channel") 446 447 var ErrRetryCountExhausted = errors.New("retry attempts exhausted") 448 449 // SelfMembershipPredicate determines whether the caller is found in the given config block 450 type SelfMembershipPredicate func(configBlock *common.Block) error 451 452 // Participant returns whether the caller participates in the chain. 453 // It receives a ChainPuller that should already be calibrated for the chain, 454 // and a SelfMembershipPredicate that is used to detect whether the caller should service the chain. 455 // It returns nil if the caller participates in the chain. 456 // It may return: 457 // ErrNotInChannel in case the caller doesn't participate in the chain. 458 // ErrForbidden in case the caller is forbidden from pulling the block. 459 // ErrServiceUnavailable in case all orderers reachable cannot complete the request. 460 // ErrRetryCountExhausted in case no orderer is reachable. 461 func Participant(puller ChainPuller, analyzeLastConfBlock SelfMembershipPredicate) error { 462 lastConfigBlock, err := PullLastConfigBlock(puller) 463 if err != nil { 464 return err 465 } 466 return analyzeLastConfBlock(lastConfigBlock) 467 } 468 469 // PullLastConfigBlock pulls the last configuration block, or returns an error on failure. 470 func PullLastConfigBlock(puller ChainPuller) (*common.Block, error) { 471 endpoint, latestHeight, err := latestHeightAndEndpoint(puller) 472 if err != nil { 473 return nil, err 474 } 475 if endpoint == "" { 476 return nil, ErrRetryCountExhausted 477 } 478 lastBlock := puller.PullBlock(latestHeight - 1) 479 if lastBlock == nil { 480 return nil, ErrRetryCountExhausted 481 } 482 lastConfNumber, err := protoutil.GetLastConfigIndexFromBlock(lastBlock) 483 if err != nil { 484 return nil, err 485 } 486 // The last config block is smaller than the latest height, 487 // and a block iterator on the server side is a sequenced one. 488 // So we need to reset the puller if we wish to pull an earlier block. 489 puller.Close() 490 lastConfigBlock := puller.PullBlock(lastConfNumber) 491 if lastConfigBlock == nil { 492 return nil, ErrRetryCountExhausted 493 } 494 return lastConfigBlock, nil 495 } 496 497 func latestHeightAndEndpoint(puller ChainPuller) (string, uint64, error) { 498 var maxHeight uint64 499 var mostUpToDateEndpoint string 500 heightsByEndpoints, err := puller.HeightsByEndpoints() 501 if err != nil { 502 return "", 0, err 503 } 504 for endpoint, height := range heightsByEndpoints { 505 if height >= maxHeight { 506 maxHeight = height 507 mostUpToDateEndpoint = endpoint 508 } 509 } 510 return mostUpToDateEndpoint, maxHeight, nil 511 } 512 513 // Close closes the ChainInspector 514 func (ci *ChainInspector) Close() { 515 ci.Puller.Close() 516 } 517 518 // ChannelGenesisBlock wraps a Block and its channel name 519 type ChannelGenesisBlock struct { 520 ChannelName string 521 GenesisBlock *common.Block 522 } 523 524 // GenesisBlocks aggregates several ChannelGenesisBlocks 525 type GenesisBlocks []ChannelGenesisBlock 526 527 // Names returns the channel names all ChannelGenesisBlocks 528 func (gbs GenesisBlocks) Names() []string { 529 var res []string 530 for _, gb := range gbs { 531 res = append(res, gb.ChannelName) 532 } 533 return res 534 } 535 536 // Channels returns the list of ChannelGenesisBlocks 537 // for all channels. Each such ChannelGenesisBlock contains 538 // the genesis block of the channel. 539 func (ci *ChainInspector) Channels() []ChannelGenesisBlock { 540 channels := make(map[string]ChannelGenesisBlock) 541 lastConfigBlockNum := ci.LastConfigBlock.Header.Number 542 var block *common.Block 543 var prevHash []byte 544 for seq := uint64(0); seq < lastConfigBlockNum; seq++ { 545 block = ci.Puller.PullBlock(seq) 546 if block == nil { 547 ci.Logger.Panicf("Failed pulling block [%d] from the system channel", seq) 548 } 549 ci.validateHashPointer(block, prevHash) 550 // Set the previous hash for the next iteration 551 prevHash = protoutil.BlockHeaderHash(block.Header) 552 553 channel, gb, err := ExtractGenesisBlock(ci.Logger, block) 554 if err != nil { 555 // If we failed to inspect a block, something is wrong in the system chain 556 // we're trying to pull, so abort. 557 ci.Logger.Panicf("Failed extracting channel genesis block from config block: %v", err) 558 } 559 560 if channel == "" { 561 ci.Logger.Info("Block", seq, "doesn't contain a new channel") 562 continue 563 } 564 565 ci.Logger.Info("Block", seq, "contains channel", channel) 566 channels[channel] = ChannelGenesisBlock{ 567 ChannelName: channel, 568 GenesisBlock: gb, 569 } 570 } 571 // At this point, block holds reference to the last block pulled. 572 // We ensure that the hash of the last block pulled, is the previous hash 573 // of the LastConfigBlock we were initialized with. 574 // We don't need to verify the entire chain of all blocks we pulled, 575 // because the block puller calls VerifyBlockHash on all blocks it pulls. 576 last2Blocks := []*common.Block{block, ci.LastConfigBlock} 577 if err := VerifyBlockHash(1, last2Blocks); err != nil { 578 ci.Logger.Panic("System channel pulled doesn't match the boot last config block:", err) 579 } 580 581 return flattenChannelMap(channels) 582 } 583 584 func (ci *ChainInspector) validateHashPointer(block *common.Block, prevHash []byte) { 585 if prevHash == nil { 586 return 587 } 588 if bytes.Equal(block.Header.PreviousHash, prevHash) { 589 return 590 } 591 ci.Logger.Panicf("Claimed previous hash of block [%d] is %x but actual previous hash is %x", 592 block.Header.Number, block.Header.PreviousHash, prevHash) 593 } 594 595 func flattenChannelMap(m map[string]ChannelGenesisBlock) []ChannelGenesisBlock { 596 var res []ChannelGenesisBlock 597 for _, csb := range m { 598 res = append(res, csb) 599 } 600 return res 601 } 602 603 // ExtractGenesisBlock determines if a config block creates new channel, in which 604 // case it returns channel name, genesis block and nil error. 605 func ExtractGenesisBlock(logger *flogging.FabricLogger, block *common.Block) (string, *common.Block, error) { 606 if block == nil { 607 return "", nil, errors.New("nil block") 608 } 609 env, err := protoutil.ExtractEnvelope(block, 0) 610 if err != nil { 611 return "", nil, err 612 } 613 payload, err := protoutil.UnmarshalPayload(env.Payload) 614 if err != nil { 615 return "", nil, err 616 } 617 if payload.Header == nil { 618 return "", nil, errors.New("nil header in payload") 619 } 620 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 621 if err != nil { 622 return "", nil, err 623 } 624 // The transaction is not orderer transaction 625 if common.HeaderType(chdr.Type) != common.HeaderType_ORDERER_TRANSACTION { 626 return "", nil, nil 627 } 628 systemChannelName := chdr.ChannelId 629 innerEnvelope, err := protoutil.UnmarshalEnvelope(payload.Data) 630 if err != nil { 631 return "", nil, err 632 } 633 innerPayload, err := protoutil.UnmarshalPayload(innerEnvelope.Payload) 634 if err != nil { 635 return "", nil, err 636 } 637 if innerPayload.Header == nil { 638 return "", nil, errors.New("inner payload's header is nil") 639 } 640 chdr, err = protoutil.UnmarshalChannelHeader(innerPayload.Header.ChannelHeader) 641 if err != nil { 642 return "", nil, err 643 } 644 // The inner payload's header should be a config transaction 645 if common.HeaderType(chdr.Type) != common.HeaderType_CONFIG { 646 logger.Warnf("Expecting %s envelope in block, got %s", common.HeaderType_CONFIG, common.HeaderType(chdr.Type)) 647 return "", nil, nil 648 } 649 // In any case, exclude all system channel transactions 650 if chdr.ChannelId == systemChannelName { 651 logger.Warnf("Expecting config envelope in %s block to target a different "+ 652 "channel other than system channel '%s'", common.HeaderType_ORDERER_TRANSACTION, systemChannelName) 653 return "", nil, nil 654 } 655 656 metadata := &common.BlockMetadata{ 657 Metadata: make([][]byte, 4), 658 } 659 metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&common.OrdererBlockMetadata{ 660 LastConfig: &common.LastConfig{Index: 0}, 661 // This is a genesis block, peer never verify this signature because we can't bootstrap 662 // trust from an earlier block, hence there are no signatures here. 663 }) 664 metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{ 665 Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 0}), 666 // This is a genesis block, peer never verify this signature because we can't bootstrap 667 // trust from an earlier block, hence there are no signatures here. 668 }) 669 670 blockdata := &common.BlockData{Data: [][]byte{payload.Data}} 671 b := &common.Block{ 672 Header: &common.BlockHeader{DataHash: protoutil.BlockDataHash(blockdata)}, 673 Data: blockdata, 674 Metadata: metadata, 675 } 676 return chdr.ChannelId, b, nil 677 }