首页 > 解决方案 > 如何通过链码以动态方式授权访问 Hyperledger Fabric 上的私有集合?

问题描述

基于此示例https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-secured-agreement/chaincode-go/asset_transfer.go我想创建一个安全的应用程序以共享私有信息。更详细地说,我用公共和私人数据创建了一个智能合约,其中所有者能够授权另一个组织访问公共集合。但是,应用程序在背书政策方面失败了。我不明白为什么会这样。有 2 个组织,每个组织有 1 个同伴。智能合约部署在测试网络(Fabric v2)上。以下是频道的操作:

./network.sh up createChannel -ca

./network.sh deployCC -ccn secured -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')"

这是我的链码:

type SmartContract struct {
    contractapi.Contract
}

type Asset struct {
    ObjectType        string `json:"objectType"` // ObjectType is used to distinguish different object types in the same chaincode namespace
    ID                string `json:"assetID"`
    Filename          string `json:"filename"`
    OwnerOrg          string `json:"ownerOrg"`
    AuthOrg           string `json:"AuthOrg"`
    PublicDescription string `json:"publicDescription"`

type PrivateAsset struct {
    ID          string `json:"assetID"`
    PrivateData string `json:"privatedata"`
}

func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetID, filename, publicDescription, authOrg string) error {
    clientOrgID, err := getClientOrgID(ctx, true)
    if err != nil {
        return fmt.Errorf("failed to get verified OrgID: %v", err)
    }

    asset := Asset{
        ObjectType:        "asset",
        ID:                assetID,
        Filename:          filename,
        OwnerOrg:          clientOrgID,
        AuthOrg:           authOrg,
        PublicDescription: publicDescription,
    }
    assetBytes, err := json.Marshal(asset)
    if err != nil {
        return fmt.Errorf("failed to create asset JSON: %v", err)
    }

    err = ctx.GetStub().PutState(asset.ID, assetBytes)
    if err != nil {
        return fmt.Errorf("failed to put asset in public data: %v", err)
    }

    return nil
}

func (s *SmartContract) CreatePrivateAsset(ctx contractapi.TransactionContextInterface, assetID, data string) error {
    transientMap, err := ctx.GetStub().GetTransient()
    if err != nil {
        return fmt.Errorf("error getting transient data: %v", err)
    }

    privatePropertiesJSON, ok := transientMap["asset_private"]
    if !ok {
        return fmt.Errorf("asset_properties key not found in the transient map")
    }

    clientOrgID, err := getClientOrgID(ctx, true)
    if err != nil {
        return fmt.Errorf("failed to get verified OrgID: %v", err)
    }
    asset, err := s.ReadAsset(ctx, assetID)
    if err != nil {
        return fmt.Errorf("failed to get asset: %v", err)
    }

    if clientOrgID != asset.OwnerOrg {
        return fmt.Errorf("a client from %s cannot sell an asset owned by %s", clientOrgID, asset.OwnerOrg)
    }

    if assetID != asset.ID {
        return fmt.Errorf("%s does not exists", assetID)
    }

    privatedata := PrivateAsset{
        ID:      assetID,
        Data: data,
    }
    assetBytes, err := json.Marshal(privatedata)
    if err != nil {
        return fmt.Errorf("failed to create asset JSON: %v", err)
    }

    err = setAssetStateBasedEndorsement(ctx, asset.ID, clientOrgID)
    if err != nil {
        return fmt.Errorf("failed setting state based endorsement for owner: %v", err)
    }

    collection := buildCollectionName(clientOrgID)
    err = ctx.GetStub().PutPrivateData(collection, asset.ID, privatePropertiesJSON)
    if err != nil {
        return fmt.Errorf("failed to put Asset private details: %v", err)
    }

    err = ctx.GetStub().PutPrivateData(collection, asset.ID, assetBytes)
    if err != nil {
        return fmt.Errorf("failed to put Asset private details: %v", err)
    }

    return nil

}

func (s *SmartContract) UpdateOrg(ctx contractapi.TransactionContextInterface, assetID string, authOrgID string) error {
    transientMap, err := ctx.GetStub().GetTransient()
    if err != nil {
        return fmt.Errorf("error getting transient: %v", err)
    }
    privatePropertiesJSON, ok := transientMap["asset_private"]
    if !ok {
        return fmt.Errorf("asset_properties key not found in the transient map")
    }

    clientOrgID, err := getClientOrgID(ctx, false)
    if err != nil {
        return fmt.Errorf("failed to get verified OrgID: %v", err)
    }

    asset, err := s.ReadAsset(ctx, assetID)
    if err != nil {
        return fmt.Errorf("failed to get asset: %v", err)
    }

    if clientOrgID != asset.OwnerOrg {
        return fmt.Errorf("a client from %s cannot update the description of a asset owned by %s", clientOrgID, asset.OwnerOrg)
    }

    asset.AuthOrg = authOrgID
    updatedAssetJSON, err := json.Marshal(asset)
    if err != nil {
        return fmt.Errorf("failed to marshal asset: %v", err)
    }
    err = ctx.GetStub().PutState(asset.ID, updatedAssetJSON)
    if err != nil {
        return fmt.Errorf("failed to put asset in public data: %v", err)
    }
    var file File
    err = json.Unmarshal(privatePropertiesJSON, &file)
    if err != nil {
        return fmt.Errorf("failed to unmarshal JSON: %s", err.Error())
    }
    collection := buildCollectionName(clientOrgID)
    immutableProperties, err := ctx.GetStub().GetPrivateData(collection, assetID)
    if err != nil {
        return fmt.Errorf("failed to read asset private properties from client org's collection: %v", err)
    }
    if immutableProperties == nil {
        return fmt.Errorf("asset private details does not exist in client org's collection: %s", assetID)
    }
    err = setAssetStateBasedEndorsement(ctx, asset.ID, authOrgID)
    if err != nil {
        return fmt.Errorf("failed setting state based endorsement for owner: %v", err)
    }
    collectionNew := buildCollectionName(authOrgID)
    err = ctx.GetStub().PutPrivateData(collectionNew, asset.ID, immutableProperties)
    if err != nil {
        return fmt.Errorf("failed to put Asset private details: %v", err)
    }

    return nil

}

func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) {
    // Since only public data is accessed in this function, no access control is required
    assetJSON, err := ctx.GetStub().GetState(assetID)
    if err != nil {
        return nil, fmt.Errorf("failed to read from world state: %v", err)
    }
    if assetJSON == nil {
        return nil, fmt.Errorf("%s does not exist", assetID)
    }
    var asset *Asset
    err = json.Unmarshal(assetJSON, &asset)
    if err != nil {
        return nil, err
    }

    return asset, nil
}

func getClientOrgID(ctx contractapi.TransactionContextInterface, verifyOrg bool) (string, error) {
    clientOrgID, err := ctx.GetClientIdentity().GetMSPID()
    if err != nil {
        return "", fmt.Errorf("failed getting client's orgID: %v", err)
    }

    if verifyOrg {
        err = verifyClientOrgMatchesPeerOrg(clientOrgID)
        if err != nil {
            return "", err
        }
    }

    return clientOrgID, nil
}

func buildCollectionName(clientOrgID string) string {
    return fmt.Sprintf("_implicit_org_%s", clientOrgID)
}

func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetID string, orgToEndorse string) error {
    endorsementPolicy, err := statebased.NewStateEP(nil)
    if err != nil {
        return err
    }
    err = endorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse)
    if err != nil {
        return fmt.Errorf("failed to add org to endorsement policy: %v", err)
    }
    policy, err := endorsementPolicy.Policy()
    if err != nil {
        return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err)
    }
    err = ctx.GetStub().SetStateValidationParameter(assetID, policy)
    if err != nil {
        return fmt.Errorf("failed to set validation parameter on asset: %v", err)
    }

    return nil
}

最后,这是关于转移的脚本的一部分:

const asset_properties_string = JSON.stringify(asset_private);
                //console.log(`${asset_properties_string}`);
                transaction = contractOrg1.createTransaction('UpdateOrg');
                //console.log(`Setting Transient map`);
                transaction.setEndorsingOrganizations(org1,org2);
                transaction.setTransient({
                    asset_private: Buffer.from(asset_properties_string)
                });
                console.log(`Wait to submit transaction`);
                await transaction.submit(asset_private.id, asset_private.authOrg);

但是,应用程序失败并显示以下输出:

失败:UpdateOrg - TransactionError:提交事务 d8f06177d7eb683590809ea943d65ad4f685126d8bda9719c552b37bd4889439 在对等 peer0.org1.example.com:7051 上失败,状态为 ENDORSEMENT_POLICY_FAILURE

PS对不起,很长的帖子,但我想详细一点

标签: hyperledger-fabrichyperledger

解决方案


推荐阅读