Fabric Gateway 使用示例

2023-12-13 15:10:38 浏览数 (2)

Fabric Gateway RPC接口简介

Fabric Gateway RPC 定义了一系列接口,这些接口提供查询和提交交易服务。交易评估(查询)需要调用Evaluate服务;交易提交(账本更新)是调用 Endorse 的两步过程随后是提交。如果出现以下情况,则需要第三步:调用 CommitStatus客户端希望等待事务被提交。在每一步之前,提案和交易必须由客户端签名。

代码语言:text复制
service Gateway {
    //Endorse 服务将提议的交易传递给网关,以便获得足够的认可。
    //网关将确定所请求链码的背书策略并转发给适当的节点以获得背书。
    //它将返回给客户端一个预执行交易结果 Envelope,其结构定义在 common/common.proto 中。
    //在调用提交服务之前,客户必须签署此信封的内容
    rpc Endorse(EndorseRequest) returns (EndorseResponse);

    //Submit 服务将处理 Endorse 服务返回的准备好的交易
    //一旦客户签名。它将等待交易提交给排序服务,但客户端必须调用 CommitStatus 服务来等待事务待提交。
    rpc Submit(SubmitRequest) returns (SubmitResponse);

    //CommitStatus 服务将指示之前提交的预处理事务是否已提交
    //如果尚未提交,它将等待提交。
    rpc CommitStatus(SignedCommitStatusRequest) returns (CommitStatusResponse);

    //评估服务将提议的事务传递到网关以调用交易函数并将结果返回给客户端。
    //如果没有账本更新操作,网关会根据区块高度和负载选择合适的peer进行查询。
    rpc Evaluate(EvaluateRequest) returns (EvaluateResponse);

    //ChaincodeEvents 服务提供一个响应流,每个响应都包含由该服务发出的请求特定块的链码的所有事件。
    //流式响应按块号升序排序。结果仅返回包含所请求事件的块,而不包含任何请求事件的块会被跳过。
    rpc ChaincodeEvents(SignedChaincodeEventsRequest) returns (stream ChaincodeEventsResponse);
}

gateway.proto文件完整定义在这里。

合约调用

fabric-gateway提供了智能合约调用接口,主要用于发起和查询上链交易,接口实现位于fabric-gateway/pkg/client/contract.go中:

代码语言:go复制
//合约代表智能合约,并允许应用程序:
//
//-使用 EvaluateTransaction() 方法评估从账本查询状态的交易。
//
//-使用 SubmitTransaction() 方法将存储状态的交易提交到分类帐。
//
//对于更复杂的事务调用,例如包含瞬态数据,可以分别使用 Evaluate() 或 Submit() 方法评估或提交事务。可以使用 SubmitAsync() 在提交到分类帐之前访问已提交事务的结果。
//
//使用 NewProposal() 可以采用更细粒度的交易流程。这允许重试流程中的各个步骤以响应错误。
//
//默认情况下,提案、事务和提交状态消息将使用连接网关时指定的签名实现进行签名。如果外部客户端持有签名凭据,则在连接网关时可以省略签名实现,并且可以通过以下方式执行离线签名:
//
//1. 将序列化的提案、事务或提交状态消息及其摘要返回给客户端
//他们生成签名。
//
//2. 使用从客户端收到的序列化消息和签名来创建签名提案、交易或
//分别使用网关的 NewSignedProposal()、NewSignedTransaction() 或 NewSignedCommit() 方法进行提交。
type Contract struct {
	client        *gatewayClient
	signingID     *signingIdentity
	channelName   string
	chaincodeName string
	contractName  string
}

//EvaluateTransaction 将评估交易函数并返回其结果。交易提案将在背书节点上进行评估,但交易不会发送到排序服务,因此不会提交到分类账。这可用于查询世界状态。
func (contract *Contract) EvaluateTransaction(name string, args ...string) ([]byte, error) 

//SubmitTransaction 会将一笔交易提交到账本,只有在提交到账本后才返回其结果。交易功能将在背书节点上进行评估,然后提交给排序服务以提交到分类账中。
//此方法可能会返回不同的错误类型,具体取决于事务调用中发生故障的点。可以使用errors.Is 或errors.As 检查错误。
func (contract *Contract) SubmitTransaction(name string, args ...string) ([]byte, error)

示例

上面介绍了 Fabric Gateway 的RPC接口,接下来以asset-transfer-basic/application-gateway-go为例,介绍下Fabric Gateway的使用过程。首先我们需要建立gRPC的链接:

代码语言:go复制
func newGRPCConnetcion() (*grpc.ClientConn, error) {
	certificate, err := loadCertificate(tlsCertPath)
	if err != nil {
		panic(err)
	}

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

	return grpc.Dial(peerEndpoint, grpc.WithTransportCredentials(transportCredentials))
}

func loadCertificate(filename string) (*x509.Certificate, error) {
	certificatePEM, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("failed to read certificate file: %w", err)
	}
	return identity.CertificateFromPEM(certificatePEM)
}

之后我们需要构建网关实例:

代码语言:go复制
gw, err := client.Connect(
	id,
	client.WithSign(sign),
	client.WithClientConnection(clientConn),
	// Default timeouts for different gRPC calls
	client.WithEvaluateTimeout(5*time.Second),
	client.WithEndorseTimeout(15*time.Second),
	client.WithSubmitTimeout(5*time.Second),
	client.WithCommitStatusTimeout(1*time.Minute),
)

Fabric使用通道来进行数据隔离,所以在创建完网关实例后,还需要根据通道名称来选择我们需要访问的网络、根据合约名称来选择需要访问的智能合约:

代码语言:go复制
network := gw.GetNetwork(channelName)
contract := network.GetContract(chaincodeName)

之后可以通过SubmitTransaction发起上链交易,EvaluateTransaction发起交易查询。

我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。


0 人点赞