You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Hyperledger Fabric中获取交易有效性详情及编写Go链码?

获取Hyperledger Fabric交易有效性详情的实现方案

为什么getHistoryForKey拿不到交易有效性

getHistoryForKey只会返回指定键的版本变更记录,包含交易ID、修改后的值和时间戳,但完全不包含交易的有效性状态。这是因为Fabric中交易的有效/无效判定是peer在区块提交阶段完成的,相关状态存储在区块的交易元数据里,而非键的版本历史中。

Go Chaincode实现代码

下面是实现两个核心功能的链code:根据交易ID查询单个交易有效性,以及查询指定键关联的所有交易有效性:

package main

import (
	"encoding/json"
	"fmt"

	"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

type SmartContract struct {
	contractapi.Contract
}

// TransactionValidity 封装交易ID、有效性状态和时间戳
type TransactionValidity struct {
	TransactionID string `json:"transactionId"`
	IsValid       bool   `json:"isValid"`
	Timestamp     int64  `json:"timestamp"`
}

// GetTransactionValidityByID 根据交易ID查询其有效性
func (s *SmartContract) GetTransactionValidityByID(ctx contractapi.TransactionContextInterface, txID string) (*TransactionValidity, error) {
	txInfo, err := ctx.GetStub().GetTransactionByID(txID)
	if err != nil {
		return nil, fmt.Errorf("获取交易信息失败: %v", err)
	}
	if txInfo == nil {
		return nil, fmt.Errorf("交易ID %s 不存在", txID)
	}

	// 获取交易验证码:0表示有效,其他值表示无效
	validationCode, err := ctx.GetStub().GetTransactionValidationCode(txID)
	if err != nil {
		return nil, fmt.Errorf("获取交易验证状态失败: %v", err)
	}

	return &TransactionValidity{
		TransactionID: txID,
		IsValid:       validationCode == 0,
		Timestamp:     txInfo.Timestamp.GetSeconds(),
	}, nil
}

// GetKeyTransactionValidities 查询指定键关联的所有交易的有效性
func (s *SmartContract) GetKeyTransactionValidities(ctx contractapi.TransactionContextInterface, key string) ([]*TransactionValidity, error) {
	historyIter, err := ctx.GetStub().GetHistoryForKey(key)
	if err != nil {
		return nil, fmt.Errorf("获取键 %s 的历史记录失败: %v", key, err)
	}
	defer historyIter.Close()

	var validityList []*TransactionValidity

	for historyIter.HasNext() {
		record, err := historyIter.Next()
		if err != nil {
			return nil, fmt.Errorf("遍历历史记录失败: %v", err)
		}

		txID := record.TxId
		validationCode, err := ctx.GetStub().GetTransactionValidationCode(txID)
		if err != nil {
			return nil, fmt.Errorf("查询交易 %s 的有效性失败: %v", txID, err)
		}

		validityList = append(validityList, &TransactionValidity{
			TransactionID: txID,
			IsValid:       validationCode == 0,
			Timestamp:     record.Timestamp.GetSeconds(),
		})
	}

	return validityList, nil
}

func main() {
	chaincode, err := contractapi.NewChaincode(&SmartContract{})
	if err != nil {
		fmt.Printf("创建链code失败: %v", err)
		return
	}

	if err := chaincode.Start(); err != nil {
		fmt.Printf("启动链code失败: %v", err)
	}
}

代码关键点说明

  • GetTransactionValidationCode是核心API:返回的验证码为0时表示交易有效,其他值(如1=无效原因、2=背书失败等)表示交易无效。
  • GetKeyTransactionValidities通过getHistoryForKey拿到键关联的所有交易ID,再逐个查询有效性,补全getHistoryForKey缺失的状态信息。

调用命令(peer容器内执行)

查询单个交易有效性

peer chaincode query -C mychannel -n mycc -c '{"Args":["GetTransactionValidityByID","tx123456"]}'

查询指定键的所有关联交易有效性

peer chaincode query -C mychannel -n mycc -c '{"Args":["GetKeyTransactionValidities","user:alice"]}'

如果必须用invoke执行(不推荐,查询类操作优先用query):

peer chaincode invoke -C mychannel -n mycc -c '{"Args":["GetTransactionValidityByID","tx123456"]}'

注意事项

  • 权限要求:默认情况下peer允许链code调用GetTransactionValidationCode,如果修改过peer的配置文件,需确保未禁用该API的访问权限。
  • 无效交易场景:无效交易不会写入世界状态,但会被记录在区块中,因此通过上述方法可以查询到这类交易的状态。
  • 性能提示:如果需要批量查询大量交易的有效性,逐个调用GetTransactionValidationCode可能存在性能瓶颈,此时可以考虑直接查询区块元数据,但该操作需要额外配置链code的权限,实现复杂度更高。

内容的提问来源于stack exchange,提问作者فواز

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 04:44:59