先描述一个层次关系如图,org2 和org1是 org50 下级

简单一个层级关系
初始化一个系统层级结构
./cmc hibe init -o wx-org50-chainmaker-org -l 5 -s ./hibe-data
生成各组织私钥
./cmc hibe genPrvKey -m 1 \
-i wx-topL \
-k ./hibe-data/wx-org50-chainmaker-org/wx-org50-chainmaker-org.masterKey \
-p ./hibe-data/wx-org50-chainmaker-org/wx-org50-chainmaker-org.params \
-o wx-org50-chainmaker-org \
-s ./hibe-data
我们基于上面wx-org50-chainmaker-org生成的私钥为直接下属wx-org1-chainmaker-org和wx-org2-chainmaker-org 分别生成私钥
####生成wx-org1-chainmaker-org
./cmc hibe genPrvKey -m 0 \
-i wx-topL/secondL \
-k ./hibe-data/wx-org50-chainmaker-org/privateKeys/wx-topL.privateKey \
-p ./hibe-data/wx-org50-chainmaker-org/wx-org50-chainmaker-org.params \
-o wx-org1-chainmaker-org \
-s ./hibe-data
####生成wx-org2-chainmaker-org
./cmc hibe genPrvKey -m 0 \
-i wx-topL/second1L \
-k ./hibe-data/wx-org50-chainmaker-org/privateKeys/wx-topL.privateKey \
-p ./hibe-data/wx-org50-chainmaker-org/wx-org50-chainmaker-org.params \
-o wx-org2-chainmaker-org \
-s ./hibe-data
注(其中-k 表示上级私钥,-p 这个如果是同一个系统,都是一样的)
最后生成的文件目录如下
├── hibe-data
│ ├── wx-org1-chainmaker-org
│ │ └── privateKeys
│ │ └── wx-topL#secondL.privateKey
│ ├── wx-org2-chainmaker-org
│ │ └── privateKeys
│ │ └── wx-topL#second1L.privateKey
│ └── wx-org50-chainmaker-org
│ ├── privateKeys
│ │ └── wx-topL.privateKey
│ ├── wx-org50-chainmaker-org.masterKey
│ └── wx-org50-chainmaker-org.params
合约编写
合约需要注意,以下方法必须存在,且是默认的,不需要修改
//export save_hibe_params
func save_params() {
params := Args()
itemMap := make(map[string]string, 0)
itemMap = EasyCodecItemToParamsMap(params)
itemBytes := EasyMarshal(params)
PutState("hibe_params", itemMap["org_id"], string(itemBytes))
}
//export find_params_by_org_id
func findParamsByOrgId() {
org_id, _ := Arg("org_id")
if result, resultCode := GetStateByte("hibe_params", org_id); resultCode != SUCCESS {
ErrorResult("错误提示 , orgId:" + org_id)
} else {
LogMessage("get val:" + string(result))
SuccessResultByte(result)
}
}
将以上合约方法复制到你的合约中,save_params() 将各组织中的params 参数上链,findParamsByOrgId 查询组织的params 参数
真正存储密文的方法如下
//export save_hibe_msg
func saveHibeMsg() {
parameters := Args()
stones := make(map[string]string)
for _, elem := range parameters {
stones[elem.Key] = elem.Value.(string)
}
items := ParamsMapToEasyCodecItem(stones)
itemsBytes := EasyMarshal(items)
logMessage(string(itemsBytes))
PutState("hibe", stones["tx_id"], string(itemsBytes))
}
其中能修改的仅仅只有saveHibeMsg方法名,和hibe 关键字,其他都不需要改,将合约部署在链上
go-sdk编写
基本流程如下 代码在chainmaker-sdk-go/sdk_hibe_test.go
params 参数上链,如果是多组织的话 所有组织的params都要上链,也就是所有组织都要调用save_hibe_params方法
fmt.Println("====================== 调用合约 params 上链 (异步)======================")
invokeUserHibeContractParams(manager_client.GetClient(),"test","save_hibe_params",txId,false)
// 上传Hibe Params
func invokeUserHibeContractParams(client *sdk.ChainClient, contractName, method, txId string, withSyncResult bool) error {
localParams, err := sdk.ReadHibeParamsWithFilePath(localHibeParamsFilePath)
if err != nil {
return err
}
payloadParams, err := client.CreateHibeInitParamsTxPayloadParams(orgId1, localParams)
resp, err := client.InvokeContract(contractName, method, txId, payloadParams, -1, withSyncResult)
if err != nil {
return err
}
if resp.Code != common.TxStatusCode_SUCCESS {
return fmt.Errorf("invoke contract failed, [code:%d]/[msg:%s]\n", resp.Code, resp.Message)
}
if !withSyncResult {
fmt.Printf("invoke contract success, resp: [code:%d]/[msg:%s]/[txId:%s]\n", resp.Code, resp.Message, resp.ContractResult.Result)
} else {
fmt.Printf("invoke contract success, resp: [code:%d]/[msg:%s]/[contractResult:%s]\n", resp.Code, resp.Message, resp.ContractResult)
}
return nil
}
加密数据上链,这里可以配置 允许哪些组织查看,我这里设置了就是 只有自己和默认的上级组织可以查看,其他组织不能查看
fmt.Println("====================== 调用合约 加密数据上链(异步)======================")
txId = sdk.GetRandTxId()
invokeUserHibeContractMsg(manager_client.GetClient(),"test","save_hibe_msg",txId,false)
func invokeUserHibeContractMsg( client *sdk.ChainClient, contractName, method, txId string, withSyncResult bool) error {
// 上链的数据有那些组织可以解,这里表示
receiverId := make([]string, 1)
receiverId[0] = localSecond1LevelId
// fetch orgId []string from receiverId []string
org := make([]string, len(receiverId))
org[0] = "wx-org2-chainmaker-org"
// query params
paramsBytesList := make([][]byte, 0)
for _, id := range org {
hibeParamsBytes, err := client.QueryHibeParamsWithOrgId(hibeContractName, findParamsByOrgId, id, -1)
if err != nil {
//t.Logf("QUERY hibe-contract-go-1 contract resp: %+v\n", hibeParams)
return fmt.Errorf("client.QueryHibeParamsWithOrgId(hibeContractName, id, -1) failed, err: %v\n", err)
}
if len(hibeParamsBytes) == 0 {
return fmt.Errorf("no souch params of %s's org, please check it", id)
}
paramsBytesList = append(paramsBytesList, hibeParamsBytes)
}
// 加密类型
keyType := crypto.SM4
params, err := client.CreateHibeTxPayloadParamsWithHibeParams([]byte(msg), receiverId, paramsBytesList, txId, keyType)
if err != nil {
return err
}
resp, err := client.InvokeContract(contractName, method, txId, params, -1, withSyncResult)
if err != nil {
return err
}
if resp.Code != common.TxStatusCode_SUCCESS {
return fmt.Errorf("invoke contract failed, [code:%d]/[msg:%s]\n", resp.Code, resp.Message)
}
if !withSyncResult {
fmt.Printf("invoke contract success, resp: [code:%d]/[msg:%s]/[txId:%s]\n", resp.Code, resp.Message, resp.ContractResult.Result)
} else {
fmt.Printf("invoke contract success, resp: [code:%d]/[msg:%s]/[contractResult:%s]\n", resp.Code, resp.Message, resp.ContractResult)
}
return nil
}
解密,特别注意解密时,并不是读取合约读写集,而是通过交易ID 来遍历交易来获取密文
fmt.Println("====================== 执行合约 加密数据查询接口 ======================")
func testUserHibeContractMsgGoQuery(t *testing.T, client *sdk.ChainClient,txId string) {
//解密算法
keyType := crypto.SM4
localParams, err := sdk.ReadHibeParamsWithFilePath(localHibeParamsFilePath)
require.Nil(t, err)
topHibePrvKey, err := sdk.ReadHibePrvKeysWithFilePath(localTopLevelHibePrvKeyFilePath)
require.Nil(t, err)
msgBytes1, err := client.DecryptHibeTxByTxId(localTopLevelId, localParams, topHibePrvKey, txId, keyType)
require.Nil(t, err)
t.Logf("QUERY hibe-contract-go-1 contract resp DecryptHibeTxByBizId [Decrypt Msg By TopLevel privateKey] message: %s\n", string(msgBytes1))
}