兄弟连区块链技术培训Fabric 1.0源代码分析(41)putils(protosutils工具包)

合集下载

兄弟连区块链教程Fabric1.0源代码分析gRPC Fabric中注册的gRPC Service一

兄弟连区块链教程Fabric1.0源代码分析gRPC Fabric中注册的gRPC Service一

兄弟连区块链教程Fabric1.0源代码分析gRPC(Fabric中注册的gRPC Service)一兄弟连区块链教程Fabric1.0源代码分析gRPC(Fabric中注册的gRPC Service)一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。

但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

# Fabric 1.0源代码笔记之 -gRPC(Fabric中注册的gRPC Service)Peer节点中注册的gRPC Service,包括:* Events Service(事件服务):Chat* Admin Service(管理服务):GetStatus、StartServer、GetModuleLogLevel、SetModuleLogLevel、RevertLogLevels* Endorser Service(背书服务):ProcessProposal* ChaincodeSupport Service(链码支持服务):Register* Gossip Service(Gossip服务):GossipStream、PingOrderer节点中注册的gRPC Service,包括:* AtomicBroadcast Service(广播服务):Broadcast、Deliver## 1、Peer节点中注册的gRPC Service### 1.1、Events Service(事件服务)#### 1.1.1、Events Service客户端```gotype EventsClient interface {// event chatting using EventChat(ctx context.Context, opts ...grpc.CallOption) (Events_ChatClient, error)}type eventsClient struct {cc *grpc.ClientConn}func NewEventsClient(cc *grpc.ClientConn) EventsClient {return &eventsClient{cc}}func (c *eventsClient) Chat(ctx context.Context, opts ...grpc.CallOption) (Events_ChatClient, error) {stream, err := grpc.NewClientStream(ctx,&_Events_serviceDesc.Streams[0], , "/protos.Events/Chat", opts...) if err != nil {return nil, err}x := &eventsChatClient{stream}return x, nil}//代码在protos/peer/events.pb.go```#### 1.1.2、Events Service服务端```gotype EventsServer interface {Chat(Events_ChatServer) error}func RegisterEventsServer(s *grpc.Server, srv EventsServer) {s.RegisterService(&_Events_serviceDesc, srv)}func _Events_Chat_Handler(srv interface{}, stream grpc.ServerStream) error {return srv.(EventsServer).Chat(&eventsChatServer{stream})}var _Events_serviceDesc = grpc.ServiceDesc{ServiceName: "protos.Events",HandlerType: (*EventsServer)(nil),Methods: []grpc.MethodDesc{},Streams: []grpc.StreamDesc{{StreamName: "Chat",Handler: _Events_Chat_Handler,ServerStreams: true,ClientStreams: true,},},Metadata: "peer/events.proto",}//代码在protos/peer/events.pb.go```### 1.2、Admin Service(管理服务)#### 1.2.1、Admin Service客户端```gotype AdminClient interface {// Return the serve status.GetStatus(ctx context.Context, in *google_protobuf.Empty,opts ...grpc.CallOption) (*ServerStatus, error)StartServer(ctx context.Context, in *google_protobuf.Empty,opts ...grpc.CallOption) (*ServerStatus, error)GetModuleLogLevel(ctx context.Context, in *LogLevelRequest,opts ...grpc.CallOption) (*LogLevelResponse, error)SetModuleLogLevel(ctx context.Context, in *LogLevelRequest,opts ...grpc.CallOption) (*LogLevelResponse, error)RevertLogLevels(ctx context.Context, in *google_protobuf.Empty,opts ...grpc.CallOption) (*google_protobuf.Empty, error)}type adminClient struct {cc *grpc.ClientConn}func NewAdminClient(cc *grpc.ClientConn) AdminClient {return &adminClient{cc}}func (c *adminClient) GetStatus(ctx context.Context, in*google_protobuf.Empty, opts ...grpc.CallOption) (*ServerStatus, error) { out := new(ServerStatus)err := grpc.Invoke(ctx, "/protos.Admin/GetStatus", in, out, , opts...)if err != nil {return nil, err}return out, nil}func (c *adminClient) StartServer(ctx context.Context, in*google_protobuf.Empty, opts ...grpc.CallOption) (*ServerStatus, error) {out := new(ServerStatus)err := grpc.Invoke(ctx, "/protos.Admin/StartServer", in, out, , opts...)if err != nil {return nil, err}return out, nil}func (c *adminClient) GetModuleLogLevel(ctx context.Context, in*LogLevelRequest, opts ...grpc.CallOption) (*LogLevelResponse, error) { out := new(LogLevelResponse)err := grpc.Invoke(ctx, "/protos.Admin/GetModuleLogLevel", in, out, , opts...)if err != nil {return nil, err}return out, nil}func (c *adminClient) SetModuleLogLevel(ctx context.Context, in*LogLevelRequest, opts ...grpc.CallOption) (*LogLevelResponse, error) { out := new(LogLevelResponse)err := grpc.Invoke(ctx, "/protos.Admin/SetModuleLogLevel", in, out, , opts...)if err != nil {return nil, err}return out, nil}func (c *adminClient) RevertLogLevels(ctx context.Context, in*google_protobuf.Empty, opts ...grpc.CallOption) (*google_protobuf.Empty, error) {out := new(google_protobuf.Empty)err := grpc.Invoke(ctx, "/protos.Admin/RevertLogLevels", in, out, , opts...)if err != nil {return nil, err}return out, nil}//代码在protos/peer/admin.pb.go```#### 1.2.2、Admin Service服务端```gotype AdminServer interface {GetStatus(context.Context, *google_protobuf.Empty) (*ServerStatus, error)StartServer(context.Context, *google_protobuf.Empty) (*ServerStatus, error)GetModuleLogLevel(context.Context, *LogLevelRequest)(*LogLevelResponse, error)SetModuleLogLevel(context.Context, *LogLevelRequest)(*LogLevelResponse, error)RevertLogLevels(context.Context, *google_protobuf.Empty)(*google_protobuf.Empty, error)}func RegisterAdminServer(s *grpc.Server, srv AdminServer) {s.RegisterService(&_Admin_serviceDesc, srv)}func _Admin_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {in := new(google_protobuf.Empty)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(AdminServer).GetStatus(ctx, in)}info := &grpc.UnaryServerInfo{Server: srv,FullMethod: "/protos.Admin/GetStatus",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(AdminServer).GetStatus(ctx,req.(*google_protobuf.Empty))}return interceptor(ctx, in, info, handler)}func _Admin_StartServer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {in := new(google_protobuf.Empty)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(AdminServer).StartServer(ctx, in)}info := &grpc.UnaryServerInfo{Server: srv,FullMethod: "/protos.Admin/StartServer",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(AdminServer).StartServer(ctx,req.(*google_protobuf.Empty))}return interceptor(ctx, in, info, handler)}func _Admin_GetModuleLogLevel_Handler(srv interface{}, ctxcontext.Context, dec func(interface{}) error, interceptorgrpc.UnaryServerInterceptor) (interface{}, error) {in := new(LogLevelRequest)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(AdminServer).GetModuleLogLevel(ctx, in)}info := &grpc.UnaryServerInfo{Server: srv,FullMethod: "/protos.Admin/GetModuleLogLevel",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(AdminServer).GetModuleLogLevel(ctx,req.(*LogLevelRequest))}return interceptor(ctx, in, info, handler)}func _Admin_SetModuleLogLevel_Handler(srv interface{}, ctxcontext.Context, dec func(interface{}) error, interceptorgrpc.UnaryServerInterceptor) (interface{}, error) {in := new(LogLevelRequest)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(AdminServer).SetModuleLogLevel(ctx, in)}info := &grpc.UnaryServerInfo{Server: srv,FullMethod: "/protos.Admin/SetModuleLogLevel",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(AdminServer).SetModuleLogLevel(ctx,req.(*LogLevelRequest))}return interceptor(ctx, in, info, handler)}func _Admin_RevertLogLevels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {in := new(google_protobuf.Empty)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(AdminServer).RevertLogLevels(ctx, in)}info := &grpc.UnaryServerInfo{Server: srv,FullMethod: "/protos.Admin/RevertLogLevels",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(AdminServer).RevertLogLevels(ctx,req.(*google_protobuf.Empty))}return interceptor(ctx, in, info, handler)}var _Admin_serviceDesc = grpc.ServiceDesc{ServiceName: "protos.Admin",HandlerType: (*AdminServer)(nil),Methods: []grpc.MethodDesc{{MethodName: "GetStatus",Handler: _Admin_GetStatus_Handler,},{MethodName: "StartServer",Handler: _Admin_StartServer_Handler,},{MethodName: "GetModuleLogLevel",Handler: _Admin_GetModuleLogLevel_Handler, },{MethodName: "SetModuleLogLevel",Handler: _Admin_SetModuleLogLevel_Handler, },{MethodName: "RevertLogLevels",Handler: _Admin_RevertLogLevels_Handler, },},Streams: []grpc.StreamDesc{},Metadata: "peer/admin.proto",}//代码在protos/peer/admin.pb.go```未完待续感谢关注兄弟连区块链教程分享!。

兄弟连区块链技术培训Fabric 1.0源代码分析(4) Chaincode(链码) platforms(链码语言平台)

兄弟连区块链技术培训Fabric 1.0源代码分析(4) Chaincode(链码) platforms(链码语言平台)

兄弟连区块链技术培训Fabric 1.0源代码分析(4)Chain code(链码)#platforms(链码语言平台)Fabric 1.0源代码笔记之 Chaincode(链码) #platforms(链码语言平台)## 1、platforms概述platforms代码集中在core/chaincode/platforms目录下。

* core/chaincode/platforms目录,链码的编写语言平台实现,如golang或java。

* platforms.go,Platform接口定义,及platforms相关工具函数。

* util目录,Docker相关工具函数。

* java目录,java语言平台实现。

* golang目录,golang语言平台实现。

## 2、Platform接口定义```gotype Platform interface {//验证ChaincodeSpecValidateSpec(spec *pb.ChaincodeSpec) error//验证ChaincodeDeploymentSpecValidateDeploymentSpec(spec *pb.ChaincodeDeploymentSpec) error//获取部署PayloadGetDeploymentPayload(spec *pb.ChaincodeSpec) ([]byte, error)//生成DockerfileGenerateDockerfile(spec *pb.ChaincodeDeploymentSpec) (string, erro r)//生成DockerBuildGenerateDockerBuild(spec *pb.ChaincodeDeploymentSpec, tw *tar.Write r) error}//代码在core/chaincode/platforms/platforms.go```## 3、platforms相关工具函数### 3.1、platforms相关工具函数```go//按链码类型构造Platform接口实例,如golang.Platform{}func Find(chaincodeType pb.ChaincodeSpec_Type) (Platform, error)//调取platform.GetDeploymentPayload(spec),获取部署Payloadfunc GetDeploymentPayload(spec *pb.ChaincodeSpec) ([]byte, error)//优先获取tls根证书,如无则获取tls证书func getPeerTLSCert() ([]byte, error)//调取platform.GenerateDockerfile(cds),创建Dockerfilefunc generateDockerfile(platform Platform, cds *pb.ChaincodeDeploymentS pec, tls bool) ([]byte, error)//调取platform.GenerateDockerBuild(cds, tw),创建DockerBuildfunc generateDockerBuild(platform Platform, cds *pb.ChaincodeDeployment Spec, inputFiles InputFiles, tw *tar.Writer) error//调取generateDockerfile(platform, cds, cert != nil)func GenerateDockerBuild(cds *pb.ChaincodeDeploymentSpec) (io.Reader, e rror)//代码在core/chaincode/platforms/platforms.go```### 3.2、Docker相关工具函数```go//contents+hash合并后再哈希func ComputeHash(contents []byte, hash []byte) []byte//哈希目录下文件并打包func HashFilesInDir(rootDir string, dir string, hash []byte, tw *tar.Wr iter) ([]byte, error)//目录是否存在func IsCodeExist(tmppath string) error//编译链码func DockerBuild(opts DockerBuildOptions) error//代码在core/chaincode/platforms/util/utils.go```func DockerBuild(opts DockerBuildOptions) error代码如下:```gotype DockerBuildOptions struct {Image stringEnv []stringCmd stringInputStream io.ReaderOutputStream io.Writer}func DockerBuild(opts DockerBuildOptions) error {client, err := cutil.NewDockerClient()if err != nil {return fmt.Errorf("Error creating docker client: %s", err)}if opts.Image == "" {//通用的本地编译环境opts.Image = cutil.GetDockerfileFromConfig("chaincode.builder") }//确认镜像是否存在或从远程拉取_, err = client.InspectImage(opts.Image)if err != nil {err = client.PullImage(docker.PullImageOptions{Repository: opts. Image}, docker.AuthConfiguration{})}//创建一个暂时的容器container, err := client.CreateContainer(docker.CreateContainerOpti ons{Config: &docker.Config{Image: opts.Image,Env: opts.Env,Cmd: []string{"/bin/sh", "-c", opts.Cmd},AttachStdout: true,AttachStderr: true,},})//删除容器defer client.RemoveContainer(docker.RemoveContainerOptions{ID: cont ainer.ID})//上传输入err = client.UploadToContainer(container.ID, docker.UploadToContain erOptions{Path: "/chaincode/input",InputStream: opts.InputStream,})stdout := bytes.NewBuffer(nil)_, err = client.AttachToContainerNonBlocking(docker.AttachToContain erOptions{Container: container.ID,OutputStream: stdout,ErrorStream: stdout,Logs: true,Stdout: true,Stderr: true,Stream: true,})//启动容器err = client.StartContainer(container.ID, nil)//等待容器返回retval, err := client.WaitContainer(container.ID)//获取容器输出err = client.DownloadFromContainer(container.ID, docker.DownloadFro mContainerOptions{Path: "/chaincode/output/.",OutputStream: opts.OutputStream,})return nil}//代码在core/chaincode/platforms/util/utils.go```## 4、golang语言平台实现### 4.1、golang.Platform结构体定义及方法Platform接口golang语言平台实现,即golang.Platform结构体定义及方法。

兄弟连区块链教程Fabric1.0源代码分析blockfile区块文件存储二

兄弟连区块链教程Fabric1.0源代码分析blockfile区块文件存储二

兄弟连区块链教程Fabric1.0源代码分析blockfile区块文件存储二兄弟连区块链教程Fabric1.0源代码分析blockfile区块文件存储二。

涉及方法如下:```go//构造blockIndexfunc newBlockIndex(indexConfig *blkstorage.IndexConfig, db*leveldbhelper.DBHandle) *blockIndex//获取最后一个块索引(或编号),取key为"indexCheckpointKey"的值,即为最新的区块编号func (index *blockIndex) getLastBlockIndexed() (uint64, error)func (index *blockIndex) indexBlock(blockIdxInfo *blockIdxInfo) error //索引区块//根据区块哈希,获取文件区块指针func (index *blockIndex) getBlockLocByHash(blockHash []byte)(*fileLocPointer, error)//根据区块编号,获取文件区块指针func (index *blockIndex) getBlockLocByBlockNum(blockNum uint64)(*fileLocPointer, error)//根据交易ID,获取文件交易指针func (index *blockIndex) getTxLoc(txID string) (*fileLocPointer, error) //根据交易ID,获取文件区块指针func (index *blockIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error)//根据区块编号和交易编号,获取文件交易指针func (index *blockIndex) getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error)//根据交易ID,获取交易验证代码func (index *blockIndex) getTxValidationCodeByTxID(txID string)(peer.TxValidationCode, error)//代码在common/ledger/blkstorage/fsblkstorage/blockindex.go```补充blockIdxInfo结构体定义:块索引信息。

兄弟连区块链教程Fabric1.0源代码分析Proposal(提案)

兄弟连区块链教程Fabric1.0源代码分析Proposal(提案)

兄弟连区块链教程Fabric1.0源代码分析Proposal(提案)兄弟连区块链教程Fabric1.0源代码分析Proposal(提案),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。

但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

# Fabric1.0源代码笔记之Proposal(提案)## 1、Proposal概述Proposal,即向Endorser发起的提案。

Proposal代码分布在protos/utils、protos/peer目录下,目录结构如下:protos/utils目录:proputils.go,Proposal工具函数。

txutils.go,Proposal工具函数。

protos/peer目录:proposal.pb.go,Proposal相关结构体定义。

## 2、Proposal相关结构体定义有个图3### 2.1、SignedProposal定义```gotype SignedProposal struct {ProposalBytes []byte //Proposal序列化,即type Proposal structSignature []byte //signer.Sign(ProposalBytes)}//代码在protos/peer/proposal.pb.go```### 2.2、Proposal定义```gotype Proposal struct {Header []byte //Header序列化,即type Header structPayload []byte //ChaincodeProposalPayload序列化,即type ChaincodeProposalPayload structExtension []byte //扩展}//代码在protos/peer/proposal.pb.go```Header更详细内容,参考:Fabric 1.0源代码笔记之 Tx(Transaction 交易)### 2.3、ChaincodeProposalPayload定义```gotype ChaincodeProposalPayload struct {Input []byte //ChaincodeInvocationSpec序列化,即type ChaincodeInvocationSpec structTransientMap map[string][]byte //瞬态映射}//代码在protos/peer/proposal.pb.go```ChaincodeInvocationSpec更详细内容,参考:Fabric 1.0源代码笔记之 Chaincode (链码)## 3、ProposalResponse结构体定义### 3.1、ProposalResponse定义```gotype ProposalResponse struct {Version int32Timestamp *google_protobuf1.TimestampResponse *Response //type Response struct,peer.Response{Status: 200, Message: "OK"}}Payload []byteEndorsement *Endorsement //type Endorsement struct}//代码在protos/peer/proposal_response.pb.go```### 3.2、Response定义```gotype Response struct { //peer.Response{Status: 200, Message: "OK"}}Status int32Message stringPayload []byte}//代码在protos/peer/proposal_response.pb.go```### 3.3、Endorsement定义```gotype Endorsement struct {Endorser []byte //bccspmsp.signerSignature []byte}//代码在protos/peer/proposal_response.pb.go ```感谢关注兄弟连区块链教程分享!。

兄弟连区块链教程Fabric1.0源代码分析流言算法Gossip服务端

兄弟连区块链教程Fabric1.0源代码分析流言算法Gossip服务端

兄弟连区块链教程Fabric1.0源代码分析流言算法Gossip服务端一兄弟连区块链教程Fabric1.0源代码分析流言算法Gossip服务端一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。

但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

# Fabric 1.0源代码笔记之 gossip(流言算法) #GossipServer(Gossip服务端)## 1、GossipServer概述GossipServer相关代码,分布在protos/gossip、gossip/comm目录下。

目录结构如下:* protos/gossip目录:* message.pb.go,GossipClient接口定义及实现,GossipServer接口定义。

* gossip/comm目录:* comm.go,Comm接口定义。

* conn.go,connFactory接口定义,以及connectionStore结构体及方法。

* comm_impl.go,commImpl结构体及方法(同时实现GossipServer接口/Comm接口/connFactory接口)。

* demux.go,ChannelDeMultiplexer结构体及方法。

## 2、GossipClient接口定义及实现### 2.1、GossipClient接口定义```gotype GossipClient interface {// GossipStream is the gRPC stream used for sending and receiving messagesGossipStream(ctx context.Context, opts ...grpc.CallOption)(Gossip_GossipStreamClient, error)// Ping is used to probe a remote peer's alivenessPing(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)}//代码在protos/gossip/message.pb.go```### 2.2、GossipClient接口实现```gotype gossipClient struct {cc *grpc.ClientConn}func NewGossipClient(cc *grpc.ClientConn) GossipClient {return &gossipClient{cc}}func (c *gossipClient) GossipStream(ctx context.Context,opts ...grpc.CallOption) (Gossip_GossipStreamClient, error) {stream, err := grpc.NewClientStream(ctx,&_Gossip_serviceDesc.Streams[0], , "/gossip.Gossip/GossipStream", opts...)if err != nil {return nil, err}x := &gossipGossipStreamClient{stream}return x, nil}func (c *gossipClient) Ping(ctx context.Context, in *Empty,opts ...grpc.CallOption) (*Empty, error) {out := new(Empty)err := grpc.Invoke(ctx, "/gossip.Gossip/Ping", in, out, , opts...) if err != nil {return nil, err}return out, nil}//代码在protos/gossip/message.pb.go```### 2.3、Gossip_GossipStreamClient接口定义及实现```gotype Gossip_GossipStreamClient interface {Send(*Envelope) errorRecv() (*Envelope, error)grpc.ClientStream}type gossipGossipStreamClient struct {grpc.ClientStream}func (x *gossipGossipStreamClient) Send(m *Envelope) error {return x.ClientStream.SendMsg(m)}func (x *gossipGossipStreamClient) Recv() (*Envelope, error) {m := new(Envelope)if err := x.ClientStream.RecvMsg(m); err != nil {return nil, err}return m, nil}//代码在protos/gossip/message.pb.go```## 3、GossipServer接口定义### 3.1、GossipServer接口定义```gotype GossipServer interface {// GossipStream is the gRPC stream used for sending and receiving messagesGossipStream(Gossip_GossipStreamServer) error// Ping is used to probe a remote peer's alivenessPing(context.Context, *Empty) (*Empty, error)}func RegisterGossipServer(s *grpc.Server, srv GossipServer) {s.RegisterService(&_Gossip_serviceDesc, srv)}func _Gossip_GossipStream_Handler(srv interface{}, streamgrpc.ServerStream) error {returnsrv.(GossipServer).GossipStream(&gossipGossipStreamServer{stream})}func _Gossip_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {in := new(Empty)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(GossipServer).Ping(ctx, in)}info := &grpc.UnaryServerInfo{Server: srv,FullMethod: "/gossip.Gossip/Ping",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(GossipServer).Ping(ctx, req.(*Empty))}return interceptor(ctx, in, info, handler)}var _Gossip_serviceDesc = grpc.ServiceDesc{ServiceName: "gossip.Gossip",HandlerType: (*GossipServer)(nil),Methods: []grpc.MethodDesc{{MethodName: "Ping",Handler: _Gossip_Ping_Handler,},},Streams: []grpc.StreamDesc{{StreamName: "GossipStream",Handler: _Gossip_GossipStream_Handler,ServerStreams: true,ClientStreams: true,},},Metadata: "gossip/message.proto",}//代码在protos/gossip/message.pb.go```### 3.2、Gossip_GossipStreamServer接口定义及实现```gotype Gossip_GossipStreamServer interface {Send(*Envelope) errorRecv() (*Envelope, error)grpc.ServerStream}type gossipGossipStreamServer struct {grpc.ServerStream}func (x *gossipGossipStreamServer) Send(m *Envelope) error {return x.ServerStream.SendMsg(m)}func (x *gossipGossipStreamServer) Recv() (*Envelope, error) { m := new(Envelope)if err := x.ServerStream.RecvMsg(m); err != nil {return nil, err}return m, nil}//代码在protos/gossip/message.pb.go```## 4、Comm接口/connFactory接口定义### 4.1、Comm接口定义```gotype Comm interface {//返回此实例的 PKI idGetPKIid() common.PKIidType//向节点发送消息Send(msg *proto.SignedGossipMessage, peers ...*RemotePeer) //探测远程节点是否有响应Probe(peer *RemotePeer) error//握手验证远程节点Handshake(peer *RemotePeer) (api.PeerIdentityType, error) Accept(common.MessageAcceptor) <-chan proto.ReceivedMessage //获取怀疑脱机节点的只读通道PresumedDead() <-chan common.PKIidType//关闭到某个节点的连接CloseConn(peer *RemotePeer)//关闭Stop()}//代码在gossip/comm/comm.go```### 4.2、connFactory接口定义```gotype connFactory interface {createConnection(endpoint string, pkiID common.PKIidType)(*connection, error)}//代码在gossip/comm/conn.go```## 5、commImpl结构体及方法(同时实现GossipServer接口/Comm接口/connFactory 接口)### 5.1、commImpl结构体定义```gotype commImpl struct {selfCertHash []bytepeerIdentity api.PeerIdentityTypeidMapper identity.Mapperlogger *logging.Loggeropts []grpc.DialOptionsecureDialOpts func() []grpc.DialOptionconnStore *connectionStorePKIID []bytedeadEndpoints chan common.PKIidTypemsgPublisher *ChannelDeMultiplexerlock *sync.RWMutexlsnr net.ListenergSrv *grpc.ServerexitChan chan struct{}stopWG sync.WaitGroupsubscriptions []chan proto.ReceivedMessageport intstopping int32}//代码在gossip/comm/comm_impl.go```未完待续欢迎继续关注兄弟连区块链教程分享!。

兄弟连区块链教程Fabric1.0源代码分析Peer peer node start命令实现

兄弟连区块链教程Fabric1.0源代码分析Peer peer node start命令实现

兄弟连区块链教程Fabric1.0源代码分析Peer peer node start命令实现兄弟连区块链教程Fabric1.0源代码分析Peer peer node start命令实现,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。

但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

# Fabric 1.0源代码笔记之 Peer #peer node start命令实现有个图2## 1、peer node加载子命令start和statuspeer node加载子命令start和status,代码如下:```gofunc Cmd() *mand {nodeCmd.AddCommand(startCmd()) //加载子命令startnodeCmd.AddCommand(statusCmd()) //加载子命令statusreturn nodeCmd}var nodeCmd = &mand{Use: nodeFuncName,Short: fmt.Sprint(shortDes),Long: fmt.Sprint(longDes),}//代码在peer/node/node.go```startCmd()代码如下:其中serve(args)为peer node start的实现代码,比较复杂,本文将重点讲解。

另statusCmd()代码与startCmd()相近,暂略。

```gofunc startCmd() *mand {flags := nodeStartCmd.Flags()flags.BoolVarP(&chaincodeDevMode, "peer-chaincodedev", "", false, "Whether peer in chaincode development mode")flags.BoolVarP(&peerDefaultChain, "peer-defaultchain", "", false, "Whether to start peer with chain testchainid")flags.StringVarP(&orderingEndpoint, "orderer", "o", "orderer:7050", "Ordering service endpoint") //ordererreturn nodeStartCmd}var nodeStartCmd = &mand{Use: "start",Short: "Starts the node.",Long: `Starts a node that interacts with the network.`,RunE: func(cmd *mand, args []string) error {return serve(args) //serve(args)为peer node start的实现代码},}//代码在peer/node/start.go```**注:如下内容均为serve(args)的代码,即peer node start命令执行流程。

兄弟连区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令

兄弟连区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令

兄弟连区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令一兄弟连区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。

但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

# Fabric 1.0源代码笔记之 Peer #peer根命令入口及加载子命令## 1、加载环境变量配置和配置文件Fabric支持通过环境变量对部分配置进行更新,如:CORE_LOGGING_LEVEL为输出的日志级别、CORE_PEER_ID为Peer的ID等。

此部分功能由第三方包viper来实现,viper除支持环境变量的配置方式外,还支持配置文件方式。

viper使用方法参考:https:///spf13/viper。

如下代码为加载环境变量配置,其中cmdRoot为"core",即CORE_开头的环境变量。

```goviper.SetEnvPrefix(cmdRoot)viper.AutomaticEnv()replacer := strings.NewReplacer(".", "_")viper.SetEnvKeyReplacer(replacer)//代码在peer/main.go```加载配置文件,同样由第三方包viper来实现,具体代码如下:其中cmdRoot为"core",即/etc/hyperledger/fabric/core.yaml。

```goerr := common.InitConfig(cmdRoot)//代码在peer/main.go```如下代码为common.InitConfig(cmdRoot)的具体实现:```goconfig.InitViper(nil, cmdRoot)err := viper.ReadInConfig()//代码在peer/common/common.go```另附config.InitViper(nil, cmdRoot)的代码实现:优先从环境变量FABRIC_CFG_PATH中获取配置文件路径,其次为当前目录、开发环境目录(即:src//hyperledger/fabric/sampleconfig)、和OfficialPath(即:/etc/hyperledger/fabric)。

兄弟连区块链教程Fabric1.0源代码分析consenter#filter

兄弟连区块链教程Fabric1.0源代码分析consenter#filter

兄弟连区块链教程Fabric1.0源代码分析consenter#filter兄弟连区块链教程Fabric1.0源代码分析consenter(共识插件)#filter(过滤器),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。

但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

# Fabric 1.0源代码笔记之 consenter(共识插件) #filter(过滤器)## 1、filter概述filter代码分布在orderer/common/filter、orderer/common/configtxfilter、orderer/common/sizefilter、orderer/common/sigfilter、orderer/multichain目录下。

orderer/common/filter/filter.go,Rule接口定义及emptyRejectRule和acceptRule实现,Committer接口定义及noopCommitter实现,RuleSet结构体及方法。

orderer/common/configtxfilter目录,configFilter结构体(实现Rule接口)及configCommitter结构体(实现Committer接口)。

orderer/common/sizefilter目录,maxBytesRule结构体(实现Rule接口)。

orderer/multichain/chainsupport.go,filter工具函数。

orderer/multichain/systemchain.go,systemChainFilter结构体(实现Rule接口)及systemChainCommitter结构体(实现Committer接口)。

## 2、Rule接口定义及实现### 2.1、Rule接口定义```gotype Action intconst (Accept = iotaRejectForward)type Rule interface { //定义一个过滤器函数, 它接受、拒绝或转发 (到下一条规则) 一个信封Apply(message *ab.Envelope) (Action, Committer)}//代码在orderer/common/filter/filter.go```### 2.2、emptyRejectRule(校验是否为空过滤器)```gotype emptyRejectRule struct{}var EmptyRejectRule = Rule(emptyRejectRule{})func (a emptyRejectRule) Apply(message *ab.Envelope) (Action, Committer) {if message.Payload == nil {return Reject, nil}return Forward, nil}//代码在orderer/common/filter/filter.go```### 2.3、acceptRule(接受过滤器)```gotype acceptRule struct{}var AcceptRule = Rule(acceptRule{})func (a acceptRule) Apply(message *ab.Envelope) (Action, Committer) {return Accept, NoopCommitter}//代码在orderer/common/filter/filter.go```### 2.4、configFilter(配置交易合法性过滤器)```gotype configFilter struct {configManager api.Manager}func NewFilter(manager api.Manager) filter.Rule //构造configFilter//配置交易过滤器func (cf *configFilter) Apply(message *cb.Envelope) (filter.Action, mitter) {msgData, err := utils.UnmarshalPayload(message.Payload) //获取Payload chdr, err :=utils.UnmarshalChannelHeader(msgData.Header.ChannelHeader) //获取ChannelHeaderif chdr.Type != int32(cb.HeaderType_CONFIG) { //配置交易return filter.Forward, nil}configEnvelope, err := configtx.UnmarshalConfigEnvelope(msgData.Data) //获取configEnvelopeerr = cf.configManager.Validate(configEnvelope) //校验configEnvelope return filter.Accept, &configCommitter{manager: cf.configManager,configEnvelope: configEnvelope,}}//代码在orderer/common/configtxfilter/filter.go```### 2.5、sizefilter(交易大小过滤器)```gotype maxBytesRule struct {support Support}func MaxBytesRule(support Support) filter.Rule //构造maxBytesRulefunc (r *maxBytesRule) Apply(message *cb.Envelope) (filter.Action, mitter) {maxBytes := r.support.BatchSize().AbsoluteMaxBytesif size := messageByteSize(message); size > maxBytes {return filter.Reject, nil}return filter.Forward, nil}//代码在orderer/common/sizefilter/sizefilter.go```### 2.6、sigFilter(签名数据校验过滤器)```gotype sigFilter struct {policySource stringpolicyManager policies.Manager}func New(policySource string, policyManager policies.Manager) filter.Rule //构造sigFilterfunc (sf *sigFilter) Apply(message *cb.Envelope) (filter.Action,mitter) {signedData, err := message.AsSignedData() //构造SignedDatapolicy, ok := sf.policyManager.GetPolicy(sf.policySource) //获取策略 err = policy.Evaluate(signedData) //校验策略if err == nil {return filter.Forward, nil}return filter.Reject, nil}//代码在orderer/common/sigfilter/sigfilter.go```### 2.7、systemChainFilter(系统链过滤器)```gotype systemChainFilter struct {cc chainCreatorsupport limitedSupport}func newSystemChainFilter(ls limitedSupport, cc chainCreator) filter.Rule //构造systemChainFilterfunc (scf *systemChainFilter) Apply(env *cb.Envelope) (filter.Action, mitter) {msgData := &cb.Payload{}err := proto.Unmarshal(env.Payload, msgData) //获取Payloadchdr, err :=utils.UnmarshalChannelHeader(msgData.Header.ChannelHeader)if chdr.Type != int32(cb.HeaderType_ORDERER_TRANSACTION){ //ORDERER_TRANSACTIONreturn filter.Forward, nil}maxChannels := scf.support.SharedConfig().MaxChannelsCount()if maxChannels > 0 {if uint64(.channelsCount()) > maxChannels {return filter.Reject, nil}}configTx := &cb.Envelope{}err = proto.Unmarshal(msgData.Data, configTx)err = scf.authorizeAndInspect(configTx)return filter.Accept, &systemChainCommitter{filter: scf,configTx: configTx,}}//代码在orderer/multichain/systemchain.go```## 3、Committer接口定义及实现### 3.1、Committer接口定义```gotype Committer interface {Commit() //提交Isolated() bool //判断交易是孤立的块,或与其他交易混合的块}//代码在orderer/common/filter/filter.go```### 3.2、noopCommitter```gotype noopCommitter struct{}var NoopCommitter = Committer(noopCommitter{})func (nc noopCommitter) Commit() {}func (nc noopCommitter) Isolated() bool { return false } //代码在orderer/common/filter/filter.go```### 3.3、configCommitter```gotype configCommitter struct {manager api.ManagerconfigEnvelope *cb.ConfigEnvelope}func (cc *configCommitter) Commit() {err := cc.manager.Apply(cc.configEnvelope)}func (cc *configCommitter) Isolated() bool {return true}//代码在orderer/common/configtxfilter/filter.go```### 3.4、systemChainCommitter```gotype systemChainCommitter struct {filter *systemChainFilterconfigTx *cb.Envelope}func (scc *systemChainCommitter) Isolated() bool {return true}func (scc *systemChainCommitter) Commit() {.newChain(scc.configTx)}//代码在orderer/multichain/systemchain.go```### 4、RuleSet结构体及方法```gotype RuleSet struct {rules []Rule}func NewRuleSet(rules []Rule) *RuleSet //构造RuleSetfunc (rs *RuleSet) Apply(message *ab.Envelope) (Committer, error) { for _, rule := range rs.rules {action, committer := rule.Apply(message)switch action {case Accept: //接受return committer, nilcase Reject: //拒绝return nil, fmt.Errorf("Rejected by rule: %T", rule)default:}}return nil, fmt.Errorf("No matching filter found")}//代码在orderer/common/filter/filter.go```### 5、filter工具函数```go//为普通 (非系统) 链创建过滤器集func createStandardFilters(ledgerResources *ledgerResources)*filter.RuleSet {return filter.NewRuleSet([]filter.Rule{filter.EmptyRejectRule, //EmptyRejectRulesizefilter.MaxBytesRule(ledgerResources.SharedConfig()),//sizefiltersigfilter.New(policies.ChannelWriters,ledgerResources.PolicyManager()), //sigfilterconfigtxfilter.NewFilter(ledgerResources), //configtxfilter filter.AcceptRule, //AcceptRule})}//为系统链创建过滤器集func createSystemChainFilters(ml *multiLedger, ledgerResources*ledgerResources) *filter.RuleSet {return filter.NewRuleSet([]filter.Rule{filter.EmptyRejectRule, //EmptyRejectRulesizefilter.MaxBytesRule(ledgerResources.SharedConfig()),//sizefiltersigfilter.New(policies.ChannelWriters,ledgerResources.PolicyManager()), //sigfilternewSystemChainFilter(ledgerResources, ml),configtxfilter.NewFilter(ledgerResources), //configtxfilter filter.AcceptRule, //AcceptRule})}//代码在orderer/multichain/chainsupport.go```。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

兄弟连区块链技术培训Fabric 1.0源代码分析(41)putils(p rotos/utils工具包)# Fabric 1.0源代码笔记之 putils(protos/utils工具包)## 1、putils概述putils,即protos/utils工具包,代码分布在:protos/utils目录下。

包括:txutils.go、proputils.go、commonutils.go、blockutils.go。

## 2、txutils```go//TransactionAction.Payload => ChaincodeActionPayload//ChaincodeActionPayload.Action.ProposalResponsePayload => ProposalResp onsePayload//ProposalResponsePayload.Extension => ChaincodeAction//从TransactionAction中获取ChaincodeActionPayload和ChaincodeAction func GetPayloads(txActions *peer.TransactionAction) (*peer.ChaincodeAct ionPayload, *peer.ChaincodeAction, error)//[]byte反序列化为Envelopefunc GetEnvelopeFromBlock(data []byte) (*common.Envelope, error)func CreateSignedEnvelope(txType common.HeaderType, channelID string, s igner crypto.LocalSigner, dataMsg proto.Message, msgVersion int32, epoc h uint64) (*common.Envelope, error)//由Proposal创建签名交易Envelopefunc CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {func CreateProposalResponse(hdrbytes []byte, payl []byte, response *pee r.Response, results []byte, events []byte, ccid *peer.ChaincodeID, visi bility []byte, signingEndorser msp.SigningIdentity) (*peer.ProposalResp onse, error)func CreateProposalResponseFailure(hdrbytes []byte, payl []byte, respon se *peer.Response, results []byte, events []byte, ccid *peer.ChaincodeI D, visibility []byte) (*peer.ProposalResponse, error)//签名Proposalfunc GetSignedProposal(prop *peer.Proposal, signer msp.SigningIdentity) (*peer.SignedProposal, error)func GetSignedEvent(evt *peer.Event, signer msp.SigningIdentity) (*peer. SignedEvent, error)func MockSignedEndorserProposalOrPanic(chainID string, cs *peer.Chainco deSpec, creator, signature []byte) (*peer.SignedProposal, *peer.Proposa l)func MockSignedEndorserProposal2OrPanic(chainID string, cs *peer.Chainc odeSpec, signer msp.SigningIdentity) (*peer.SignedProposal, *peer.Propo sal)func GetBytesProposalPayloadForTx(payload *peer.ChaincodeProposalPayloa d, visibility []byte) ([]byte, error)func GetProposalHash2(header *common.Header, ccPropPayl []byte) ([]byt e, error)func GetProposalHash1(header *common.Header, ccPropPayl []byte, visibil ity []byte) ([]byte, error)//代码在protos/utils/txutils.go```## 3、proputils```gofunc GetChaincodeInvocationSpec(prop *peer.Proposal) (*peer.ChaincodeIn vocationSpec, error)func GetChaincodeProposalContext(prop *peer.Proposal) ([]byte, map[stri ng][]byte, error)//反序列化为common.Headerfunc GetHeader(bytes []byte) (*common.Header, error)func GetNonce(prop *peer.Proposal) ([]byte, error)//Header.ChannelHeader反序列化为peer.ChaincodeHeaderExtensionfunc GetChaincodeHeaderExtension(hdr *common.Header) (*peer.ChaincodeHe aderExtension, error)func GetProposalResponse(prBytes []byte) (*peer.ProposalResponse, erro r)func GetChaincodeDeploymentSpec(code []byte) (*peer.ChaincodeDeployment Spec, error)func GetChaincodeAction(caBytes []byte) (*peer.ChaincodeAction, error) func GetResponse(resBytes []byte) (*peer.Response, error)func GetChaincodeEvents(eBytes []byte) (*peer.ChaincodeEvent, error) func GetProposalResponsePayload(prpBytes []byte) (*peer.ProposalRespons ePayload, error)func GetProposal(propBytes []byte) (*peer.Proposal, error)//e.Payload反序列化为Payloadfunc GetPayload(e *common.Envelope) (*common.Payload, error)//[]byte反序列化为Transactionfunc GetTransaction(txBytes []byte) (*peer.Transaction, error)func GetChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionP ayload, error)//反序列化为peer.ChaincodeProposalPayloadfunc GetChaincodeProposalPayload(bytes []byte) (*peer.ChaincodeProposal Payload, error)//反序列化为common.SignatureHeaderfunc GetSignatureHeader(bytes []byte) (*common.SignatureHeader, error) func CreateChaincodeProposal(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, strin g, error)func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainI D string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientM ap map[string][]byte) (*peer.Proposal, string, error)func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, n once, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error)func GetBytesProposalResponsePayload(hash []byte, response *peer.Respon se, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, erro r)func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayloa d) ([]byte, error)func GetBytesResponse(res *peer.Response) ([]byte, error)func GetBytesChaincodeEvent(event *peer.ChaincodeEvent) ([]byte, error) func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error)func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, erro r)func GetBytesProposal(prop *peer.Proposal) ([]byte, error)func GetBytesHeader(hdr *common.Header) ([]byte, error)func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, erro r)func GetBytesTransaction(tx *peer.Transaction) ([]byte, error)func GetBytesPayload(payl *common.Payload) ([]byte, error)func GetBytesEnvelope(env *common.Envelope) ([]byte, error)//从envBytes []byte中获取ChaincodeActionfunc GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, err or)func CreateProposalFromCIS(typ common.HeaderType, chainID string, cis * peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error)func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error)//按ChaincodeDeploymentSpec创建DeployProposalfunc CreateDeployProposalFromCDS(chainID string, cds *peer.ChaincodeDep loymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error)func CreateUpgradeProposalFromCDS(chainID string, cds *peer.ChaincodeDe ploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error)func createProposalFromCDS(chainID string, msg proto.Message, creator [] byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer. Proposal, string, error)func ComputeProposalTxID(nonce, creator []byte) (string, error)func CheckProposalTxID(txid string, nonce, creator []byte) errorfunc ComputeProposalBinding(proposal *peer.Proposal) ([]byte, error) func computeProposalBindingInternal(nonce, creator []byte, epoch uint64) ([]byte, error)//代码在protos/utils/proputils.go```## 4、commonutils```gofunc MarshalOrPanic(pb proto.Message) []bytefunc Marshal(pb proto.Message) ([]byte, error)func CreateNonceOrPanic() []bytefunc CreateNonce() ([]byte, error)func UnmarshalPayloadOrPanic(encoded []byte) *cb.Payloadfunc UnmarshalPayload(encoded []byte) (*cb.Payload, error)func UnmarshalEnvelopeOrPanic(encoded []byte) *cb.Envelopefunc UnmarshalEnvelope(encoded []byte) (*cb.Envelope, error)func UnmarshalEnvelopeOfType(envelope *cb.Envelope, headerType cb.Heade rType, message proto.Message) (*cb.ChannelHeader, error)func ExtractEnvelopeOrPanic(block *cb.Block, index int) *cb.Envelope func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) func ExtractPayloadOrPanic(envelope *cb.Envelope) *cb.Payloadfunc ExtractPayload(envelope *cb.Envelope) (*cb.Payload, error)func MakeChannelHeader(headerType cb.HeaderType, version int32, chainID string, epoch uint64) *cb.ChannelHeaderfunc MakeSignatureHeader(serializedCreatorCertChain []byte, nonce []byt e) *cb.SignatureHeaderfunc SetTxID(channelHeader *cb.ChannelHeader, signatureHeader *cb.Signa tureHeader) errorfunc MakePayloadHeader(ch *cb.ChannelHeader, sh *cb.SignatureHeader) *c b.Headerfunc NewSignatureHeaderOrPanic(signer crypto.LocalSigner) *cb.Signature Headerfunc SignOrPanic(signer crypto.LocalSigner, msg []byte) []byte//[]byte反序列化为ChannelHeaderfunc UnmarshalChannelHeader(bytes []byte) (*cb.ChannelHeader, error) func UnmarshalChaincodeID(bytes []byte) (*pb.ChaincodeID, error)func IsConfigBlock(block *cb.Block) bool//代码在protos/utils/commonutils.go```## 5、blockutils```go//[]byte转换为Block,从Block中获取ChainID(即ChannelId)func GetChainIDFromBlockBytes(bytes []byte) (string, error)//从Block中获取ChainID(即ChannelId)func GetChainIDFromBlock(block *cb.Block) (string, error)//从Block中按index获取Metadatafunc GetMetadataFromBlock(block *cb.Block, index cb.BlockMetadataIndex) (*cb.Metadata, error)//从Block中按index获取Metadata,如果失败则Panicfunc GetMetadataFromBlockOrPanic(block *cb.Block, index cb.BlockMetadat aIndex) *cb.Metadata//从Block.Metadata.Metadata中获取LastConfigfunc GetLastConfigIndexFromBlock(block *cb.Block) (uint64, error)//从Block.Metadata.Metadata中获取LastConfig,如果失败则Panicfunc GetLastConfigIndexFromBlockOrPanic(block *cb.Block) uint64//[]byte转换为Blockfunc GetBlockFromBlockBytes(blockBytes []byte) (*cb.Block, error)//拷贝Block.Metadatafunc CopyBlockMetadata(src *cb.Block, dst *cb.Block)//初始化Block.Metadata.Metadatafunc InitBlockMetadata(block *cb.Block)//代码在protos/utils/blockutils.go。

相关文档
最新文档