fabric 2.0, peer channel command

Peer Channel Create

Towards Orderer -o 127.0.0.1:7050

$ peer channel create -c test1 -o 127.0.0.1:7050
var channelCmd = &cobra.Command{
	Use:   "channel",
	Short: "Operate a channel: create|fetch|join|list|update|signconfigtx|getinfo.",
	Long:  "Operate a channel: create|fetch|join|list|update|signconfigtx|getinfo.",
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		common.InitCmd(cmd, args)
		common.SetOrdererEnv(cmd, args)
	},
}

create

InitCmdFactory needs to be done before executeCreate(cf). It has to set up the RPC with orderer.

func create(cmd *cobra.Command, args []string, cf *ChannelCmdFactory) error {
	// the global chainID filled by the "-c" command
	if channelID == common.UndefinedParamValue {
		return errors.New("must supply channel ID")
	}
	// Parsing of the command line is done so silence cmd usage
	cmd.SilenceUsage = true

	var err error
	if cf == nil {
		cf, err = InitCmdFactory(EndorserNotRequired, PeerDeliverNotRequired, OrdererRequired)
		if err != nil {
			return err
		}
	}
	return executeCreate(cf)
}

InitCmdFactory

Do some initialization. DeliverClient will be created from an orderClient.Deliver(), but BroadcastClient is not set here. Instead it will be instantiatized if need. Similar as DeliverClient, it will be created from orderClient.Broadcast(). Both DeliverC and BroadcastC will create a RPC/TCP connection towards Orderer. Thus, we will set up two underlying TCP connections…

// 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
}

// GetBroadcastClient creates a simple instance of the BroadcastClient interface
func GetBroadcastClient() (BroadcastClient, error) {
	oc, err := NewOrdererClientFromEnv()
	if err != nil {
		return nil, err
	}
	bc, err := oc.Broadcast()
	if err != nil {
		return nil, err
	}

	return &BroadcastGRPCClient{Client: bc}, nil
}

executeCreate

CreateChain --> GetGenesisBlock --> Persist block data to local disk


func executeCreate(cf *ChannelCmdFactory) error {
	err := sendCreateChainTransaction(cf)
	if err != nil {
		return err
	}

	block, err := getGenesisBlock(cf)
	if err != nil {
		return err
	}

	b, err := proto.Marshal(block)
	if err != nil {
		return err
	}

	file := channelID + ".block"
	if outputBlock != common.UndefinedParamValue {
		file = outputBlock
	}
	err = ioutil.WriteFile(file, b, 0644)
	if err != nil {
		return err
	}

	return nil
}

Peer Channel fetch

Fetch a block of the channel specified, towards Orderer -o 127.0.0.1:7050 or if order address is not specified, it will fetch from the peer deliver service

peer channel fetch 0 -o 127.0.0.1:7050 -c test5

call stack

github.com/hyperledger/fabric/common/deliver.(*Handler).deliverBlocks at deliver.go:201
github.com/hyperledger/fabric/common/deliver.(*Handler).Handle at deliver.go:174
github.com/hyperledger/fabric/orderer/common/server.(*server).Deliver at server.go:209
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-protos-go/orderer._AtomicBroadcast_Deliver_Handler at ab.pb.go:674
github.com/hyperledger/fabric/common/grpclogging.StreamServerInterceptor.func1 at server.go:130
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainStreamServer.func1.1.1 at chain.go:49
github.com/hyperledger/fabric/common/grpcmetrics.StreamServerInterceptor.func1 at interceptor.go:65
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainStreamServer.func1.1.1 at chain.go:49
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainStreamServer.func1 at chain.go:58
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).processStreamingRPC at server.go:1206
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).handleStream at server.go:1279
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).serveStreams.func1.1 at server.go:710
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).serveStreams.func1 at server.go:708

If tryting to fetch a block which doesn’t exist, it will hang up waiting for the block. It is actualy a cond variable, which can be waken up by cond.broadcast(), when the waited block is available, or the cusor/iterator is closed.

// Next moves the cursor to next block and returns true iff the iterator is not exhausted
func (itr *blocksItr) Next() (ledger.QueryResult, error) {
	if itr.maxBlockNumAvailable < itr.blockNumToRetrieve {
		itr.maxBlockNumAvailable = itr.waitForBlock(itr.blockNumToRetrieve)
	}
	...

Peer channel getinfo

Towards endorser

peer channel getinfo -c test1
func getinfo(cmd *cobra.Command, cf *ChannelCmdFactory) error {
	//the global chainID filled by the "-c" command
	if channelID == common.UndefinedParamValue {
		return errors.New("Must supply channel ID")
	}
	// Parsing of the command line is done so silence cmd usage
	cmd.SilenceUsage = true
	var err error
	if cf == nil {
		cf, err = InitCmdFactory(EndorserRequired, PeerDeliverNotRequired, OrdererNotRequired)
		if err != nil {
			return err
		}
	}

	client := &endorserClient{cf}

	blockChainInfo, err := client.getBlockChainInfo()

Peer channel list

–> endorser

It will eventually invoke ChainCode ‘cscc’, “GetChannel” method… See the call stack below:

github.com/hyperledger/fabric/core/chaincode.(*Handler).serialSendAsync at handler.go:307
github.com/hyperledger/fabric/core/chaincode.(*Handler).Execute at handler.go:1207
github.com/hyperledger/fabric/core/chaincode.(*ChaincodeSupport).execute at chaincode_support.go:272
github.com/hyperledger/fabric/core/chaincode.(*ChaincodeSupport).Invoke at chaincode_support.go:202
github.com/hyperledger/fabric/core/chaincode.(*ChaincodeSupport).Execute at chaincode_support.go:155
github.com/hyperledger/fabric/core/endorser.(*SupportImpl).Execute at support.go:126
github.com/hyperledger/fabric/core/endorser.(*Endorser).callChaincode at endorser.go:119
github.com/hyperledger/fabric/core/endorser.(*Endorser).SimulateProposal at endorser.go:187
github.com/hyperledger/fabric/core/endorser.(*Endorser).ProcessProposalSuccessfullyOrError at endorser.go:397
github.com/hyperledger/fabric/core/endorser.(*Endorser).ProcessProposal at endorser.go:340
github.com/hyperledger/fabric/core/handlers/auth/filter.(*expirationCheckFilter).ProcessProposal at expiration.go:61
github.com/hyperledger/fabric/core/handlers/auth/filter.(*filter).ProcessProposal at filter.go:32
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-protos-go/peer._Endorser_ProcessProposal_Handler.func1 at peer.pb.go:107
github.com/hyperledger/fabric/internal/peer/node.unaryGrpcLimiter.func1 at grpc_limiters.go:51
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainUnaryServer.func1.1.1 at chain.go:25
github.com/hyperledger/fabric/common/grpclogging.UnaryServerInterceptor.func1 at server.go:92
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainUnaryServer.func1.1.1 at chain.go:25
github.com/hyperledger/fabric/common/grpcmetrics.UnaryServerInterceptor.func1 at interceptor.go:31
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainUnaryServer.func1.1.1 at chain.go:25
github.com/hyperledger/fabric/vendor/github.com/grpc-ecosystem/go-grpc-middleware.ChainUnaryServer.func1 at chain.go:34
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-protos-go/peer._Endorser_ProcessProposal_Handler at peer.pb.go:109
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).processUnaryRPC at server.go:995
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).handleStream at server.go:1275
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).serveStreams.func1.1 at server.go:710
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/hyperledger/fabric/vendor/google.golang.org/grpc.(*Server).serveStreams.func1 at server.go:708

Msg will be asyncSent out, to system chain code for further processing.

// serialSendAsync serves the same purpose as serialSend (serialize msgs so gRPC will
// be happy). In addition, it is also asynchronous so send-remoterecv--localrecv loop
// can be nonblocking. Only errors need to be handled and these are handled by
// communication on supplied error channel. A typical use will be a non-blocking or
// nil channel
func (h *Handler) serialSendAsync(msg *pb.ChaincodeMessage) {
	go func() {
		if err := h.serialSend(msg); err != nil {
			// provide an error response to the caller
			resp := &pb.ChaincodeMessage{
				Type:      pb.ChaincodeMessage_ERROR,
				Payload:   []byte(err.Error()),
				Txid:      msg.Txid,
				ChannelId: msg.ChannelId,
			}
			h.Notify(resp)

			// surface send error to stream processing
			h.errChan <- err
		}
	}()
}

System ChainCode

System Chain code is deployed as below:

// DeploySysCC is the hook for system chaincodes where system chaincodes are registered with the fabric.
// This call directly registers the chaincode with the chaincode handler and bypasses the other usercc constructs.
func DeploySysCC(sysCC SelfDescribingSysCC, chaincodeStreamHandler ChaincodeStreamHandler) {
	sysccLogger.Infof("deploying system chaincode '%s'", sysCC.Name())

	ccid := ChaincodeID(sysCC.Name())
	done := chaincodeStreamHandler.LaunchInProc(ccid)

	peerRcvCCSend := make(chan *pb.ChaincodeMessage)
	ccRcvPeerSend := make(chan *pb.ChaincodeMessage)

	go func() {
		stream := newInProcStream(peerRcvCCSend, ccRcvPeerSend)
		defer stream.CloseSend()

		sysccLogger.Debugf("starting chaincode-support stream for  %s", ccid)
		err := chaincodeStreamHandler.HandleChaincodeStream(stream)
		sysccLogger.Criticalf("shim stream ended with err: %v", err)
	}()

	go func(sysCC SelfDescribingSysCC) {
		stream := newInProcStream(ccRcvPeerSend, peerRcvCCSend)
		defer stream.CloseSend()

		sysccLogger.Debugf("chaincode started for %s", ccid)
		err := shim.StartInProc(ccid, stream, sysCC.Chaincode())
		sysccLogger.Criticalf("system chaincode ended with err: %v", err)
	}(sysCC)
	<-done
}
  • chaincodeStreamHandler takes peerRcvCCSend as receiver and ccRcvPeerSend as sender.
  • shim takes ccRcvPeerSend as receiver and peerRcvCCSend as sender
  • This makes the two switch their send/receive

shim.ChatWithPeer will process the message:


// chat stream for peer-chaincode interactions post connection
func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode) error {
	msgAvail := make(chan *recvMsg, 1)
	errc := make(chan error)

	receiveMessage := func() {
		in, err := stream.Recv()
		msgAvail <- &recvMsg{in, err}
	}
	go receiveMessage()
	for {
		select {
		case rmsg := <-msgAvail:
			switch {
			case rmsg.err == io.EOF:
				return errors.New("received EOF, ending chaincode stream")
			case rmsg.err != nil:
				err := fmt.Errorf("receive failed: %s", rmsg.err)
				return err
			case rmsg.msg == nil:
				err := errors.New("received nil message, ending chaincode stream")
				return err
			default:
				err := handler.handleMessage(rmsg.msg, errc)
				if err != nil {
					err = fmt.Errorf("error handling message: %s", err)
					return err
				}

				go receiveMessage()
			}

		case sendErr := <-errc:
			if sendErr != nil {
				err := fmt.Errorf("error sending: %s", sendErr)
				return err
			}
		}
	}
}

shim.Handler

It will invoke the system chain code

Call stack
github.com/hyperledger/fabric/core/peer.(*Peer).GetChannelsInfo at peer.go:412
github.com/hyperledger/fabric/core/scc/cscc.(*PeerConfiger).getChannels at configure.go:297
github.com/hyperledger/fabric/core/scc/cscc.(*PeerConfiger).InvokeNoShim at configure.go:190
github.com/hyperledger/fabric/core/scc/cscc.(*PeerConfiger).Invoke at configure.go:132
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleTransaction at handler.go:209
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleTransaction-fm at handler.go:195
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleStubInteraction at handler.go:159
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleReady at handler.go:620

Peer channel join

–> endorser

peer channel join -b test5_0.block
call stack of shim handler
github.com/hyperledger/fabric/core/scc/cscc.(*PeerConfiger).joinChain at configure.go:245
github.com/hyperledger/fabric/core/scc/cscc.(*PeerConfiger).InvokeNoShim at configure.go:176
github.com/hyperledger/fabric/core/scc/cscc.(*PeerConfiger).Invoke at configure.go:132
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleTransaction at handler.go:209
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleTransaction-fm at handler.go:195
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleStubInteraction at handler.go:159
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/hyperledger/fabric/vendor/github.com/hyperledger/fabric-chaincode-go/shim.(*Handler).handleReady at handler.go:620

after joining channel, peer/endorser will start gossip service, if it gets elected as leader, it will start delivering for channel

StartDeliverForChannel() will try fetching block vis Orderer.Deliver service.

func (g *GossipService) onStatusChangeFactory(channelID string, committer blocksprovider.LedgerInfo) func(bool) {
	return func(isLeader bool) {
		if isLeader {
			yield := func() {
				g.lock.RLock()
				le := g.leaderElection[channelID]
				g.lock.RUnlock()
				le.Yield()
			}
			logger.Info("Elected as a leader, starting delivery service for channel", channelID)
			if err := g.deliveryService[channelID].StartDeliverForChannel(channelID, committer, yield); err != nil {
				logger.Errorf("Delivery service is not able to start blocks delivery for chain, due to %+v", err)
			}
		} else {
			logger.Info("Renounced leadership, stopping delivery service for channel", channelID)
			if err := g.deliveryService[channelID].StopDeliverForChannel(channelID); err != nil {
				logger.Errorf("Delivery service is not able to stop blocks delivery for chain, due to %+v", err)
			}
		}
	}
}
发布了28 篇原创文章 · 获赞 6 · 访问量 2959

猜你喜欢

转载自blog.csdn.net/m0_37889044/article/details/104671802
今日推荐