Hyperledger fabric2.4 链码调用与fabric-gateway

前面的文章实现了如何搭建自己的区块链网络,使用命令行或SDK创建通道、安装部署链码。链码调用有两种方式:通道客户端调用和fabric-gateway调用。以官方示例sacc链码为例,需要初始化的链码必须先初始化,代码参考上篇。

1、通过通道客户端调用

使用通道客户端调用链码函数为同步调用,响应时间与区块生成时间大致相同。

package main

import (
	"fmt"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
	"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
	"log"
	"os"
)

func main() {
	// 通道名称
	var channelID = "mychannel"
	// 组织名称
	var orgName = "Org1"
	// 组织用户
	var orgUser = "User1"
	// 链码名称
	var ChaincodeID = "sacc"

	// 初始化sdk
	sdk, err := fabsdk.New(config.FromFile("./sdkInit/config.yaml"))
	if err != nil {
		log.Fatalf("初始化fabric sdk失败,error:%v", err)
	}

	// 实例化通道客户端
	clientChannelContext := sdk.ChannelContext(channelID, fabsdk.WithUser(orgUser), fabsdk.WithOrg(orgName))
	// Channel client is used to query and execute transactions (Org1 is default org)
	client, err := channel.New(clientChannelContext)
	if err != nil {
		log.Fatalf("通道客户端创建失败: %s", err)
		os.Exit(-1)
	}

	// 调用链码 set 函数, 设置a的值为100
	req := channel.Request{ChaincodeID: ChaincodeID, Fcn: "set", Args: [][]byte{[]byte("a"), []byte("100")}}
	respone, err := client.Execute(req)
	// 打印交易ID
	fmt.Println("set Txid:", respone.TransactionID)

	// 调用链码 get 函数,查询a的值
	req1 := channel.Request{ChaincodeID: ChaincodeID, Fcn: "get", Args: [][]byte{[]byte("a")}}
	respone1, err := client.Query(req1)
	fmt.Println("a的值:", string(respone1.Payload))
}

通过fabric-gateway调用

fabric-gateway调用链码有以下几个方法:

  • SubmitSync:将事务提交到账本,并在成功发送到后立即返回结果,此方法为异步提交,提交成功后数据并没有立即保存到账本
  • SubmitTransaction:将交易提交到账本,并仅在将其提交到账本后返回结果,同步提交
  • EvaluateTransaction:查询指定数据,key不存在时报错
package main

import (
	"crypto/x509"
	"fmt"
	"github.com/hyperledger/fabric-gateway/pkg/client"
	"github.com/hyperledger/fabric-gateway/pkg/identity"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"io/ioutil"
	"log"
	"path"
	"time"
)

var (
	// 组织的MSPID
	mspID = "Org1MSP"
	// 中间变量
	cryptoPath = "./fixtures/crypto-config/peerOrganizations"
	// client 用户的签名证书
	certPath = "/org1.maakees.com/users/[email protected]/msp/signcerts/[email protected]"
	// client 用户的私钥路径
	keyPath = "/org1.maakees.com/users/[email protected]/msp/keystore/"
	// client 用户的 tls 通信证书
	tlsCertPath = "/org1.maakees.com/users/[email protected]/msp/tlscacerts/tlsca.org1.maakees.com-cert.pem"
	// 所连 peer 节点的地址
	peerEndpoint = "localhost:7051"
	// 网关 peer 节点名称
	gatewayPeer = "peer0.org1.maakees.com"
	// 连接的通道
	channelName = "mychannel"
	// 链码名称
	chaincodeName = "sacc"
)

func main() {
	clientConnection := newGrpcConnection()
	defer clientConnection.Close()

	id := newIdentity()
	sign := newSign()

	gateway, err := client.Connect(
		id,
		client.WithSign(sign),
		client.WithClientConnection(clientConnection),
		client.WithEvaluateTimeout(5*time.Second),
		client.WithEndorseTimeout(15*time.Second),
		client.WithSubmitTimeout(5*time.Second),
		client.WithCommitStatusTimeout(1*time.Minute),
	)
	if err != nil {
		log.Fatalf("client.Connect error: %s", err)
	}
	defer gateway.Close()

	network := gateway.GetNetwork(channelName)
	sacc := network.GetContract(chaincodeName)

	// 调用链码 set 函数,设置b的值为1000
	_, err = sacc.SubmitTransaction("set", "b", "1000")
	if err != nil {
		log.Fatalln(err)
	}

	// 调用链码 get 函数,查询b的值
	res1, err := sacc.EvaluateTransaction("get", "b")
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(string(res1))
}

// 创建指gRPC连接.
func newGrpcConnection() *grpc.ClientConn {
	certificate, err := loadCertificate(cryptoPath + tlsCertPath)
	if err != nil {
		panic(err)
	}

	certPool := x509.NewCertPool()
	certPool.AddCert(certificate)
	transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer)

	connection, err := grpc.Dial(peerEndpoint, grpc.WithTransportCredentials(transportCredentials))
	if err != nil {
		panic(fmt.Errorf("failed to create gRPC connection: %w", err))
	}

	return connection
}

// 创建客户端标识。
func newIdentity() *identity.X509Identity {
	certificate, err := loadCertificate(cryptoPath + certPath)
	if err != nil {
		panic(err)
	}

	id, err := identity.NewX509Identity(mspID, certificate)
	if err != nil {
		panic(err)
	}
	return id
}

// 加载证书文件
func loadCertificate(filename string) (*x509.Certificate, error) {
	certificatePEM, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("failed to read certificate file: %w", err)
	}
	return identity.CertificateFromPEM(certificatePEM)
}

// 使用私钥生成签名
func newSign() identity.Sign {
	files, err := ioutil.ReadDir(cryptoPath + keyPath)
	if err != nil {
		panic(fmt.Errorf("failed to read private key directory: %w", err))
	}
	privateKeyPEM, err := ioutil.ReadFile(path.Join(cryptoPath+keyPath, files[0].Name()))

	if err != nil {
		panic(fmt.Errorf("failed to read private key file: %w", err))
	}

	privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM)
	if err != nil {
		panic(err)
	}

	sign, err := identity.NewPrivateKeySign(privateKey)
	if err != nil {
		panic(err)
	}

	return sign
}

你可能感兴趣的:(Hyperledger,Fabric,fabric,golang,区块链)