如何在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,提问作者فواز
相关产品推荐
相关产品推荐

