链码是什么

链码是一段程序,由Go、node.js或Java编写,来实现一些预定义的接口。链码运行在一个和背书节点分开的独立进程中,通过应用程序提交的交易来初始化和管理账本状态。

链码可以在提案交易中被调用用来升级或者查询账本。赋予适当的权限,链码就可以调用其他链码访问它的状态,不管是在同一个通道还是不同的通道。注意,如果被调用链码和调用链码在不同的通道,就只能执行只读查询。就是说,调用不同通道的链码只能进行“查询”,在提交的子语句中不能参与状态的合法性检查。

Chaincode API

每一个链码程序都必须实现 Chaincode 接口,该接口的方法在接收到交易时会被调用 。

在每种语言中,客户端提交交易提案(transaction proposal)都会调用 Invoke 方法。该方法可以让你使用链码来读写通道账本上的数据。

你还需要包含Init方法,该方法是实例化方法。该方法是链码接口需要的,你的应用程序没有必要调用 。你可以使用Fabric链码生命周期过程来指定在Invoke之前是否必须调用Init方法。

接下来以Go语言为例,看一下如何编写链码:

内务

首先从内务开始。每一个链码都要实现Chaincode接口中的Init和Invoke方法。所以,我们先使用Go import语句来导入链码必要的依赖。我们将导入链码shim包和peer protobuf包,这是我们写链码必须要导入的两个包,我们所有用的API都在这两个包里。然后,我们加入一个SimpleAsset结构体来作为Chaincode shim方法的接收者。这个结构体可以什么也不写。

初始化链码

然后,我们将实现Init方法。

注意:链码升级的时候也要调用这个方法,当写一个用来升级已存在的链码的时候,清确保合理更改Init方法。特别地,当升级时没有“迁移”或者没东西需要初始化时,可以提供一个空的Init方法。

接下来,我们将使用ChaincodeStubInterface.GetStringArgs方法获取Init调用的参数,并且检查其合法性。在下面的用例中,我们希望得到一个键值对:

接下来,我们已经确定了调用是合法的,我们将把初始状态存入账本中。我们将调用ChaincodeStubInterface.PutState并将键和值作为参数传递给它。假设一切正常,将返回一个peer.Response对象,表明初始化成功。

(注意:Fabric数据库默认为levelDB)

调用链码

首先,我们增加一个Invoke函数的签名。

就像上面的Init函数一样,我们需要从ChaincodeStubInterface中解析参数。Invoke函数的参数是将要调用的链码应用程序的函数名。在我们的用例中,我们的应用程序将有两个方法:set和get,用来设置或者获取资产当前的状态。我们先调用ChaincodeStubInterface.GetFunctionAndParameters来为链码应用程序的方法解析方法名和参数。

然后,我们将验证函数名是否为set或者get,并执行链码应用程序的方法,通过shim.Success或shim.Error返回一个适当的响应,这个响应被序列化为gRPC protobuf消息。

 Invoke方法会根据方法名为你调用相应的函数方法。(就像一个管家一样,你只需要告诉它我需要调用哪个方法,并把参数告诉它,它会帮你去调用这个方法)。

实现链码应用程序

像我们上面所说的,我们的链码应用程序实现了两个功能,它们可以通过Invoke方法调用。我们现在来实现这些方法。注意我们之前提到的,要访问账本状态,我们需要使用链码shim API中的ChaincodeStubInterface.PuState和ChaincodeStubInterface.GetState方法。

把它们组合在一起

最后,我们增加一个main方法,它将调用shim.Start方法,该方法参数中new的内容是链码的名称。下边是该链码程序的完整源码。

还要注意,链码中的package必须是main package,不可以是其他package。

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐