Fabric-sdk-go操作Chaincode

因为工作的需要,最近了解了下如何通过sdk来操作Chaincode,本文是sdk使用时的一些操作总结。

在fabric网络启动过程中,一般分为“启动网络 -> 创建通道 -> 加入通道 -> 安装链码 -> 实例化链码 -> 调用链码”。本文以fabric-sdk-go项目中的end_to_end.go为例,介绍如何通过fabric-sdk-go来使用链码。

创建sdk实例

使用sdk的第一步是创建sdk实例

sdk, err := fabsdk.New(configOpt, sdkOpts...)
if err != nil {
	t.Fatalf("Failed to create new SDK: %s", err)
}
defer sdk.Close()

创建通道并安装链码

end_to_end.go中,这一步是通过createChannelAndCC()来实现的。

首先是使用提供的身份凭证来创建事务用于之后的操作:

clientContext := sdk.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(ordererOrgName))

接着使用上一步创建的事务来创建一个资源管理客户端(resmgmt.Client)

resMgmtClient, err := resmgmt.New(clientContext)

接着createChannel()创建通道。在创建通道时,需要使用该组织的管理员用户创建,主要用到GetSigningIdentity()SaveChannel()方法:

func createChannel(t *testing.T, sdk *fabsdk.FabricSDK, resMgmtClient *resmgmt.Client) {
	mspClient, err := mspclient.New(sdk.Context(), mspclient.WithOrg(orgName))
	if err != nil {
		t.Fatal(err)
	}
	adminIdentity, err := mspClient.GetSigningIdentity(orgAdmin)
	if err != nil {
		t.Fatal(err)
	}
	req := resmgmt.SaveChannelRequest{ChannelID: channelID,
		ChannelConfigPath: integration.GetChannelConfigTxPath(channelID + ".tx"),
		SigningIdentities: []msp.SigningIdentity{adminIdentity}}
	txID, err := resMgmtClient.SaveChannel(req, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint("orderer.example.com"))
	require.Nil(t, err, "error should be nil")
	require.NotEmpty(t, txID, "transaction ID should be populated")
}

加入通道

通道创建成功后,需要将将组织添加到通道中,主要用到JoinChannel()

adminContext := sdk.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(orgName))

// Org resource management client
orgResMgmt, err := resmgmt.New(adminContext)
......

	// Org peers join channel
err = orgResMgmt.JoinChannel(channelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint("orderer.example.com")) 
......

创建链码

完成上述的操作,接下来就是链码相关的操作了。

与命令行下的链码操作不同,sdk安装链码时并不需要事先将链码程序放到背书节点,而是在调用InstallCCRequest()时再将本地的链码打包安装到背书节点:

func createCC(t *testing.T, orgResMgmt *resmgmt.Client) {
    // Packing the example cc from local
    // argv[0]: cc path in local
    // argv[1]: GOPATH
	ccPkg, err := packager.NewCCPackage("github.com/example_cc", integration.GetDeployPath())
	......
	// Install example cc to org peers
	installCCReq := resmgmt.InstallCCRequest{Name: ccID, Path: "github.com/example_cc", Version: "0", Package: ccPkg}
	_, err = orgResMgmt.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
	......
	// Set up chaincode policy
	ccPolicy := cauthdsl.SignedByAnyMember([]string{"Org1MSP"})
	// Org resource manager will instantiate 'example_cc' on channel
	resp, err := orgResMgmt.InstantiateCC(
		channelID,
		resmgmt.InstantiateCCRequest{Name: ccID, Path: "github.com/example_cc", Version: "0", Args: integration.ExampleCCInitArgs(), Policy: ccPolicy},
		resmgmt.WithRetry(retry.DefaultResMgmtOpts),
	)
	......
}

链码调用

链码调用,这里推荐使用Execute()

func executeCC(t *testing.T, client *channel.Client) {
	_, err := client.Execute(channel.Request{ChaincodeID: ccID, Fcn: "invoke", Args: integration.ExampleCCDefaultTxArgs()},
		channel.WithRetry(retry.DefaultChannelOpts))
	if err != nil {
		t.Fatalf("Failed to move funds: %s", err)
	}
}

示例

这个例子是使用sdk操作fabric-samples中的fabcar链码,其中省略了创建和加入通道的操作。

执行go run main.go后,输出结果如下:

result

本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可。

posted @ 2020-06-14 16:46  落雷  阅读(3115)  评论(0编辑  收藏  举报