183 lines
5.9 KiB
Go
183 lines
5.9 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package channel
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
cb "github.com/hyperledger/fabric-protos-go/common"
|
|
pb "github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric/common/flogging"
|
|
"github.com/hyperledger/fabric/internal/peer/common"
|
|
"github.com/hyperledger/fabric/msp"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
var logger = flogging.MustGetLogger("channelCmd")
|
|
|
|
const (
|
|
EndorserRequired bool = true
|
|
EndorserNotRequired bool = false
|
|
OrdererRequired bool = true
|
|
OrdererNotRequired bool = false
|
|
PeerDeliverRequired bool = true
|
|
PeerDeliverNotRequired bool = false
|
|
)
|
|
|
|
var (
|
|
// join related variables.
|
|
genesisBlockPath string
|
|
|
|
// joinbysnapshot related variables
|
|
snapshotPath string
|
|
|
|
// create related variables
|
|
channelID string
|
|
channelTxFile string
|
|
outputBlock string
|
|
timeout time.Duration
|
|
|
|
// fetch related variables
|
|
bestEffort bool
|
|
)
|
|
|
|
// Cmd returns the cobra command for Node
|
|
func Cmd(cf *ChannelCmdFactory) *cobra.Command {
|
|
AddFlags(channelCmd)
|
|
|
|
channelCmd.AddCommand(createCmd(cf))
|
|
channelCmd.AddCommand(fetchCmd(cf))
|
|
channelCmd.AddCommand(joinCmd(cf))
|
|
channelCmd.AddCommand(joinBySnapshotCmd(cf))
|
|
channelCmd.AddCommand(joinBySnapshotStatusCmd(cf))
|
|
channelCmd.AddCommand(listCmd(cf))
|
|
channelCmd.AddCommand(updateCmd(cf))
|
|
channelCmd.AddCommand(signconfigtxCmd(cf))
|
|
channelCmd.AddCommand(getinfoCmd(cf))
|
|
|
|
return channelCmd
|
|
}
|
|
|
|
// AddFlags adds flags for create and join
|
|
func AddFlags(cmd *cobra.Command) {
|
|
common.AddOrdererFlags(cmd)
|
|
}
|
|
|
|
var flags *pflag.FlagSet
|
|
|
|
func init() {
|
|
resetFlags()
|
|
}
|
|
|
|
// Explicitly define a method to facilitate tests
|
|
func resetFlags() {
|
|
flags = &pflag.FlagSet{}
|
|
|
|
flags.StringVarP(&genesisBlockPath, "blockpath", "b", common.UndefinedParamValue, "Path to file containing genesis block")
|
|
flags.StringVarP(&snapshotPath, "snapshotpath", "", common.UndefinedParamValue, "Path to the snapshot directory")
|
|
flags.StringVarP(&channelID, "channelID", "c", common.UndefinedParamValue, "In case of a newChain command, the channel ID to create. It must be all lower case, less than 250 characters long and match the regular expression: [a-z][a-z0-9.-]*")
|
|
flags.StringVarP(&channelTxFile, "file", "f", "", "Configuration transaction file generated by a tool such as configtxgen for submitting to orderer")
|
|
flags.StringVarP(&outputBlock, "outputBlock", "", common.UndefinedParamValue, `The path to write the genesis block for the channel. (default ./<channelID>.block)`)
|
|
flags.DurationVarP(&timeout, "timeout", "t", 10*time.Second, "Channel creation timeout")
|
|
flags.BoolVarP(&bestEffort, "bestEffort", "", false, "Whether fetch requests should ignore errors and return blocks on a best effort basis")
|
|
}
|
|
|
|
func attachFlags(cmd *cobra.Command, names []string) {
|
|
cmdFlags := cmd.Flags()
|
|
for _, name := range names {
|
|
if flag := flags.Lookup(name); flag != nil {
|
|
cmdFlags.AddFlag(flag)
|
|
} else {
|
|
logger.Fatalf("Could not find flag '%s' to attach to commond '%s'", name, cmd.Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
var channelCmd = &cobra.Command{
|
|
Use: "channel",
|
|
Short: "Operate a channel: create|fetch|join|joinbysnapshot|joinbysnapshotstatus|list|update|signconfigtx|getinfo.",
|
|
Long: "Operate a channel: create|fetch|join|joinbysnapshot|joinbysnapshotstatus|list|update|signconfigtx|getinfo.",
|
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
|
common.InitCmd(cmd, args)
|
|
common.SetOrdererEnv(cmd, args)
|
|
},
|
|
}
|
|
|
|
type BroadcastClientFactory func() (common.BroadcastClient, error)
|
|
|
|
type deliverClientIntf interface {
|
|
GetSpecifiedBlock(num uint64) (*cb.Block, error)
|
|
GetOldestBlock() (*cb.Block, error)
|
|
GetNewestBlock() (*cb.Block, error)
|
|
Close() error
|
|
}
|
|
|
|
// ChannelCmdFactory holds the clients used by ChannelCmdFactory
|
|
type ChannelCmdFactory struct {
|
|
EndorserClient pb.EndorserClient
|
|
Signer msp.SigningIdentity
|
|
BroadcastClient common.BroadcastClient
|
|
DeliverClient deliverClientIntf
|
|
BroadcastFactory BroadcastClientFactory
|
|
}
|
|
|
|
// InitCmdFactory init the ChannelCmdFactory with clients to endorser and orderer according to params
|
|
func InitCmdFactory(isEndorserRequired, isPeerDeliverRequired, isOrdererRequired bool) (*ChannelCmdFactory, error) {
|
|
if isPeerDeliverRequired && isOrdererRequired {
|
|
// this is likely a bug during development caused by adding a new cmd
|
|
return nil, errors.New("ERROR - only a single deliver source is currently supported")
|
|
}
|
|
|
|
var err error
|
|
cf := &ChannelCmdFactory{}
|
|
|
|
cf.Signer, err = common.GetDefaultSignerFnc()
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, "error getting default signer")
|
|
}
|
|
|
|
cf.BroadcastFactory = func() (common.BroadcastClient, error) {
|
|
return common.GetBroadcastClientFnc()
|
|
}
|
|
|
|
// for join and list, we need the endorser as well
|
|
if isEndorserRequired {
|
|
// creating an EndorserClient with these empty parameters will create a
|
|
// connection using the values of "peer.address" and
|
|
// "peer.tls.rootcert.file"
|
|
cf.EndorserClient, err = common.GetEndorserClientFnc(common.UndefinedParamValue, common.UndefinedParamValue)
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, "error getting endorser client for channel")
|
|
}
|
|
}
|
|
|
|
// for fetching blocks from a peer
|
|
if isPeerDeliverRequired {
|
|
cf.DeliverClient, err = common.NewDeliverClientForPeer(channelID, cf.Signer, bestEffort)
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, "error getting deliver client for channel")
|
|
}
|
|
}
|
|
|
|
// for create and fetch, we need the orderer as well
|
|
if isOrdererRequired {
|
|
if len(strings.Split(common.OrderingEndpoint, ":")) != 2 {
|
|
return nil, errors.Errorf("ordering service endpoint %s is not valid or missing", common.OrderingEndpoint)
|
|
}
|
|
cf.DeliverClient, err = common.NewDeliverClientForOrderer(channelID, cf.Signer, bestEffort)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
logger.Infof("Endorser and orderer connections initialized")
|
|
return cf, nil
|
|
}
|