重庆分公司,新征程启航

为企业提供网站建设、域名注册、服务器等服务

go语言链码方法,go语言链表

Fabric源码分析之Peer链码安装

environment:

创新互联公司提供成都做网站、网站制作、网页设计,品牌网站设计1元广告等致力于企业网站建设与公司网站制作,十载的网站开发和建站经验,助力企业信息化建设,成功案例突破近千家,是您实现网站建设的好选择.

fabric v1.4.2

在Fabric中交易的处理过程,客户端将提案首先发送到背书节点,背书节点检提案的合法性。如果合法的话,背书节点将通过交易所属的链码临时执行一个交易,并执行背书节点在本地持有的状态副本。

Chaincode应该仅仅被安装于chaincode所有者的背书节点上,链码运行在节点上的沙盒(Docker容器)中,并通过gRPC协议与相应的Peer节点进行交互,以使该chaincode逻辑对整个网络的其他成员保密。

请务必在一条channel上每一个要运行你chaincode的背书节点上安装你的chaincode

其他没有chaincode的成员将无权成为chaincode影响下的交易的认证节点(endorser)。也就是说,他们不能执行chaincode。不过,他们仍可以验证交易并提交到账本上。

ChainCode要在区块链网络中运行,需要经过链码安装和链码实例化两个步骤。

链码的安装涉及到3个服务,分别是client,peer背书节点和LSCC容器

主要流程:

以下是在客户端执行 "peer chaincode install ..." 的业务流程图:

客户端执行链码安装命令:

客户端的整个流程切入点为 fabric/peer/main.go 的 main 函数

然后继续找到 peer/chaincode/chaincode.go

继续找到 peer/chaincode/install.go 的 installCmd 函数,可以看出 chaincodeInstall 为主要的入口函数

我们进去看看 InitCmdFactory 做了什么,位置在 peer/chaincode/common.go

返回了 ChaincodeCmdFactory 的结构体,定义为:

找到定义 genChaincodeDeploymentSpec

先看 getChaincodeSpec ,位于 peer/chaincode/common.go

封装返回 ChaincodeSpec 结构体

刚才生成的 ChaincodeSpec 作为 getChaincodeDeploymentSpec 函数的输入参数,返回 ChaincodeDeploymentSpec 结构体

CreateInstallProposalFromCDS 位于 protos/utils/proutils.go

调用 createProposalFromCDS

从结构体 ChaincodeInvocationSpec 可以看到用户链码安装需要调用到系统链码 lscc

通过 CreateProposalFromCIS=CreateChaincodeProposal=CreateChaincodeProposalWithTransient

再看 CreateChaincodeProposalWithTxIDNonceAndTransient 函数

最后返回 Proposal 结构体,定义见 protos\peer\proposal.pb.go

到这里 install 调用的 CreateInstallProposalFromCDS 完毕,返回 Proposal 结构体

关系有点复杂,给出一个类图能看得清晰点

回到 install ,看 GetSignedProposal 对刚创建的提案结构进行签名

函数位于 protos/utils/txutils.go

返回 SignedProposal 结构体,定义位于 protos/peer/proposal.pb.go

提案签名完后 install 调用 ProcessProposal 发送提案到peer节点进行处理,参数带了 SignedProposal 结构体

接下来client端就等到peer的 proposalResponse

当client调用了 ProposalResponse 消息就发送到peer背书节点,也就是走peer节点背书提案流程.

要看安装链码前做了什么,直接看 peer节点背书提案流程 就好。

我们从 core/endorser/endorser.go 的 callChaincode=Execute 函数开始讲

在 core/chaincode/chaincode_support.go 找到 Execute

主要看 Invoke :

根据之前的信息,我们调用的是 lscc 来安装链码,所以在peer启动的时候已经初始化 lscc 链码容器了,所以回直接返回 handler 对象,后面的语句就不说了,在启动链码容器的章节再详细研究。

接着我们看 execute 函数,调用 createCCMessage 创建一个 ChaincodeMessage结构体消息 . Execute 负责把消息发送出去

在 core/chaincode/handler.go 找到 Execute

这里关键是 h.serialSendAsync(msg) 语句,功能是把包装好的信息以grpc协议发送出去,直接就等返回结果了。

至此 Execute 调用的 Invoke 就在等返回结果,结果返回就调用 processChaincodeExecutionResult 对链码结果进行处理

peer发送的信息哪去了呢?

我们定位到 code/chaincode/shim/chaincode.go ,我们看到两个入口函数 Start 和 StartInProc , Start 为用户链码的入口函数,而 StartInProc 是系统链码的入口函数,他们同时都调用了 chatWithPeer ,因为我们调用的是lscc,就看 StartInProc

chatWithPeer就是开启grpc的接收模式在等到节点发来信息,接收到信息后就调用 handleMessage 处理信息。

因为我们信息类型为 ChaincodeMessage_TRANSACTION ,所以我们在 core/chaincode/shim/handler.go 顺着 handleMessage=handleReady 扎到 handleTransaction

其中关键语句 res := handler.cc.Invoke(stub) ,这语句是调用相应链码的 Invoke 函数,所以我们找到 core/scc/lscc/lscc.go 下的 Invoke 函数

进去 core/scc/lscc/lscc.go 的 Invoke 函数可以看到,这里有 "INSTALL", "DEPLOY", "UPGRADE" 等操作,我们只看 INSTALL 部分。

关键调用函数是 executeInstall

接着看 executeInstall

HandleChaincodeInstall 为处理statedb,而 PutChaincodeToLocalStorage 是把链码文件安装到本地文件目录

链码安装到peer的默认路径 /var/hyperledger/production/chaincodes

到此链码的安装完毕

lscc链码安装完毕后,返回信息给peer节点,peer节点就给提案背书返回给client服务端,至此链码安装完毕。

github

参考:

5-ChainCode生命周期、分类及安装、实例化命令解析

fabric源码解读【peer chaincode】:安装链码

Fabric1.4源码解析:客户端安装链码

fabric-sdk-go的简单使用

使用fabric提供的cryptogen工具生成文件模板

$ cryptogen showtemplate crypto-config.yaml

进行修改,添加一个组织,一个orderer节点.

根据crypto-config.yaml文件生成证书文件:

$ cryptogen generate --config=crypto-config.yaml

查看生成的证书文件夹结构:

需要从fabric的源码案例中拷贝configtx.yaml文件

$ cp $GOPATH/src/github.com/hyperledger/fabric-samples/first-network/configtx.yaml ./

对configtx.yaml文件进行修改.

修改之前,创建一个文件夹,来保存即将创建的创世区块文件

将创建区块文件和通道的命令写到一个脚本中! generate.sh

脚本文件和配置文件的目录结构:

执行generate.sh文件生成创世区块文件和通道,其实只有一个组织,也没必要生成锚节点更新文件..

$ ./generate.sh

配置docker-compose文件:

启动容器, 启动后查看容器运行情况

$ docker-compose up -d

$ docker-compose ps

在这里,创建两个脚本文件,用于docker容器的管理

clear_docker.sh 文件:

restart.sh 文件:

创建配置文件的时候,有两个文件可以进行参考...

修改后的sdk配置文件:

创建出一个模型对象,给其赋值,并开始初始化sdk

使用 pkg/fabsdk/fabsdk.go中的New()方法进行实例化

创建请求之前,需要使用 gopackager.NewCCPackage 方法生成一个resource.CCPackage 对象,传递两个参数,一个是链码的路径(相对于工程的路径), 一个是GOPATH的路径.

安装链码,使用pkg/client/resmgmt/resmgmt.go文件中的方法

创建请求之前,需要生成一个*cb.SignaturePolicyEnvelope类型的对象,使用 third_party/github.com/hyperledger/fabric/common/cauthdsl/cauthdsl_builder.go 文件中的方法即可,提供了好几个方法, 使用任意一个即可.这里使用 SignedByAnyMember 方法: 需要传入所属组织ID

实例化链码

使用 pkg/client/channel/chclient.go 中的 Execute() 方法,来进行数据写入的操作:

rsp, err := model.Channelclient.Execute(req)

写入之前,要创建请求:

tempArgs是要传给链码的参数,可以做下封装,就不受参数个数的限制了

使用 pkg/client/channel/chclient.go 中的 Query() 方法,来进行数据查询的操作: 查询之前,同样需要创建请求.

链码在工程中的路径应该是 工程名/chaincode文件夹

比如:

driverFabricDemo/chaincode

而不应该省略掉工程名这样写: chaincode

错误原因:cert.URIs 和 tpl.URIs 这两个字段没有被定义.

进入tpl对象中, /usr/local/go/src/crypto/x509/x509.go 是个结构体,并没有发现 URIs 字段

对go版本进行升级,从1.9.3升级到1.11.3, 再次进入 /usr/local/go/src/crypto/x509/x509.go 文件中,查看结构体内容:

在执行sdk的Excute()方法时报错.

方法不存在,一般是由于链码的Invoke方法中的方法名和Excute()方法传入的方法名不一样.

但是可以肯定的是,链码的Invoke方法中的方法名和,项目中执行Excute()方法时传入的方法名是完全一样的! 但是很奇怪了,为什么会出现这个错误呢? 使用 docker rmi 删除掉 dev-peerx.travle.xq.com 的镜像,再重新运行即可.

在创建实例化链码请求的时候

总是提示

Cannot use str (type *cb.SignaturePolicyEnvelope) as type *common.SignaturePolicyEnvelope less... (⌘F1) Inspection info: Reports composite literals with incompatible types and values

明明是相同的类型,却总是报错,应该是IDE的问题.把vendor文件夹删除后,就不会有提示了. 再使用vendor对工程进行init 和 add +external 就好了!!

出现这个错误,一般都是配置文件哪个地方写错了,需要细心检查

go语言聊天室实现(六)创建HTTP连接,并升级为长连接

我们在mian函数中,首先初始化配置文件,然后新建http连接。

这个连接创建之后,监听服务器的9999端口。如果url的路径后缀为 "/ws",就转发到ws/ws.go中的IndexHandler方法中。

这个方法中首先我们创建一个websocket的Upgrader实例,然后我们使用Upgrader的upgrade方法来升级一下我们的连接为长连接。

升级完成之后会返回一个*websocket.Conn的连接,我们之后所有的关于连接的操作,都是基于该conn的。

在该连接完成之后,我们将连接存放到一个名为Client的map中,以便之后管理更为方便。

之后,我们启动一个goroutine来读取连接中发送的信息内容,再根据内容进行相应的操作。

Go语言list(列表)

2021-11-10

列表是一种非连续的存储容器,有多个节点组成,节点通过一些变量记录彼此之间的关系

单链表和双链表就是列表的两种方法。

原理:A、B、C三个人,B懂A的电话,C懂B的电话只是单方知道号码,这样就形成了一个单链表结构。

如果C把自己的号码给B,B把自己的号码给A,因为是双方都知道对方的号码,这样就形成了一个双链表结构

如果B换号码了,他需要通知AC,把自己的号码删了,这个过程就是列表的删除操作。

在Go语言中,列表使用 container/list 包来实现,内部的实现原理是双链表,列表能够高效地进行任意位置的元素插入和删除操作。

列表初始化的两种办法

列表没有给出具体的元素类型的限制,所以列表的元素可以是任意类型的,

例如给列表中放入了一个 interface{} 类型的值,取出值后,如果要将 interface{} 转换为其他类型将会发生宕机。

双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront 和 PushBack。

列表插入函数的返回值会提供一个 *list.Element 结构,这个结构记录着列表元素的值以及与其他节点之间的关系等信息,从列表中删除元素时,需要用到这个结构进行快速删除。

遍历完也能看到最后的结果

学习地址:

Go语言基础语法(一)

本文介绍一些Go语言的基础语法。

先来看一个简单的go语言代码:

go语言的注释方法:

代码执行结果:

下面来进一步介绍go的基础语法。

go语言中格式化输出可以使用 fmt 和 log 这两个标准库,

常用方法:

示例代码:

执行结果:

更多格式化方法可以访问中的fmt包。

log包实现了简单的日志服务,也提供了一些格式化输出的方法。

执行结果:

下面来介绍一下go的数据类型

下表列出了go语言的数据类型:

int、float、bool、string、数组和struct属于值类型,这些类型的变量直接指向存在内存中的值;slice、map、chan、pointer等是引用类型,存储的是一个地址,这个地址存储最终的值。

常量是在程序编译时就确定下来的值,程序运行时无法改变。

执行结果:

执行结果:

Go 语言的运算符主要包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符以及指针相关运算符。

算术运算符:

关系运算符:

逻辑运算符:

位运算符:

赋值运算符:

指针相关运算符:

下面介绍一下go语言中的if语句和switch语句。另外还有一种控制语句叫select语句,通常与通道联用,这里不做介绍。

if语法格式如下:

if ... else :

else if:

示例代码:

语法格式:

另外,添加 fallthrough 会强制执行后面的 case 语句,不管下一条case语句是否为true。

示例代码:

执行结果:

下面介绍几种循环语句:

执行结果:

执行结果:

也可以通过标记退出循环:

--THE END--


分享题目:go语言链码方法,go语言链表
浏览路径:http://cqcxhl.cn/article/hscdph.html

其他资讯

在线咨询
服务热线
服务热线:028-86922220
TOP