Skip to content

Commit

Permalink
[FAB-12635] Inspect channels of system chain
Browse files Browse the repository at this point in the history
This change set adds support for inspecting all channels
inside a system chain.

It pulls all blocks of the system channel, and then inspects
the blocks and returns all blocks that are creations of new channels.

Change-Id: I714f4f1537be3d7e2d88046561c155545e2f2037
Signed-off-by: yacovm <yacovm@il.ibm.com>
  • Loading branch information
yacovm authored and guoger committed Oct 29, 2018
1 parent a65b055 commit d92a41d
Show file tree
Hide file tree
Showing 4 changed files with 524 additions and 0 deletions.
31 changes: 31 additions & 0 deletions orderer/common/cluster/mocks/chain_puller.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

113 changes: 113 additions & 0 deletions orderer/common/cluster/replication.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/core/comm"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -84,3 +85,115 @@ type NoopBlockVerifier struct{}
func (*NoopBlockVerifier) VerifyBlockSignature(sd []*common.SignedData, config *common.ConfigEnvelope) error {
return nil
}

//go:generate mockery -dir . -name ChainPuller -case underscore -output mocks/

// ChainPuller pulls blocks from a chain
type ChainPuller interface {
// PullBlock pulls the given block from some orderer node
PullBlock(seq uint64) *common.Block
// Close closes the ChainPuller
Close()
}

// ChainInspector walks over a chain
type ChainInspector struct {
Logger *flogging.FabricLogger
Puller ChainPuller
LastConfigBlock *common.Block
}

// Channels returns the list of channels
// that exist in the chain
func (cw *ChainInspector) Channels() []string {
channels := make(map[string]struct{})
lastConfigBlockNum := cw.LastConfigBlock.Header.Number
var block *common.Block
for seq := uint64(1); seq < lastConfigBlockNum; seq++ {
block = cw.Puller.PullBlock(seq)
channel, err := IsNewChannelBlock(block)
if err != nil {
// If we failed to classify a block, something is wrong in the system chain
// we're trying to pull, so abort.
cw.Logger.Panic("Failed classifying block", seq, ":", err)
continue
}
if channel == "" {
cw.Logger.Info("Block", seq, "doesn't contain a new channel")
continue
}
cw.Logger.Info("Block", seq, "contains channel", channel)
channels[channel] = struct{}{}
}
// At this point, block holds reference to the last block pulled.
// We ensure that the hash of the last block pulled, is the previous hash
// of the LastConfigBlock we were initialized with.
// We don't need to verify the entire chain of all blocks we pulled,
// because the block puller calls VerifyBlockHash on all blocks it pulls.
last2Blocks := []*common.Block{block, cw.LastConfigBlock}
if err := VerifyBlockHash(1, last2Blocks); err != nil {
cw.Logger.Panic("System channel pulled doesn't match the boot last config block:", err)
}

return flattenChannelMap(channels)
}

func flattenChannelMap(m map[string]struct{}) []string {
var res []string
for channel := range m {
res = append(res, channel)
}
return res
}

// IsNewChannelBlock returns a name of the channel in case
// it holds a channel create transaction, or empty string otherwise.
func IsNewChannelBlock(block *common.Block) (string, error) {
if block == nil {
return "", errors.New("nil block")
}
env, err := utils.ExtractEnvelope(block, 0)
if err != nil {
return "", err
}
payload, err := utils.ExtractPayload(env)
if err != nil {
return "", err
}
if payload.Header == nil {
return "", errors.New("nil header in payload")
}
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return "", err
}
// The transaction is an orderer transaction
if common.HeaderType(chdr.Type) != common.HeaderType_ORDERER_TRANSACTION {
return "", nil
}
systemChannelName := chdr.ChannelId
innerEnvelope, err := utils.UnmarshalEnvelope(payload.Data)
if err != nil {
return "", err
}
innerPayload, err := utils.UnmarshalPayload(innerEnvelope.Payload)
if err != nil {
return "", err
}
if innerPayload.Header == nil {
return "", errors.New("inner payload's header is nil")
}
chdr, err = utils.UnmarshalChannelHeader(innerPayload.Header.ChannelHeader)
if err != nil {
return "", err
}
// The inner payload's header is a config transaction
if common.HeaderType(chdr.Type) != common.HeaderType_CONFIG {
return "", nil
}
// In any case, exclude all system channel transactions
if chdr.ChannelId == systemChannelName {
return "", nil
}
return chdr.ChannelId, nil
}
Loading

0 comments on commit d92a41d

Please sign in to comment.