mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 07:25:10 +00:00
Add in examples and notes on using PurgePrivateData (#878)
* Add in examples and notes on using PurgePrivateData - Update the configtx.yaml to enable the 2.5 capabillity - Added purge into the chancode - Added pruge into the application client code. Signed-off-by: Matthew B White <whitemat@uk.ibm.com> * Temporarily remove java cc test Signed-off-by: Matthew B White <whitemat@uk.ibm.com>
This commit is contained in:
parent
124adb43f9
commit
795673dee3
10 changed files with 149 additions and 24 deletions
|
|
@ -129,6 +129,10 @@ async function main(): Promise<void> {
|
|||
|
||||
// Delete AssetID2 as Org1.
|
||||
await deleteAsset(contractOrg1, assetID2);
|
||||
|
||||
// Trigger a purge of the private data for the asset
|
||||
// The previous delete is optinal if purge is used
|
||||
await purgeAsset(contractOrg1, assetID2);
|
||||
} finally {
|
||||
gatewayOrg1.close();
|
||||
clientOrg1.close();
|
||||
|
|
@ -261,6 +265,17 @@ async function deleteAsset(contract: Contract, assetID: string): Promise<void> {
|
|||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
async function purgeAsset(contract: Contract, assetID: string): Promise<void> {
|
||||
console.log('\n--> Submit Transaction: PurgeAsset, ID:', assetID);
|
||||
const dataForPurge = { assetID };
|
||||
await contract.submit('PurgeAsset', {
|
||||
transientData: { asset_purge: JSON.stringify(dataForPurge) },
|
||||
});
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
async function readAssetPrivateDetails(contract: Contract, assetID: string, collectionName: string): Promise<boolean> {
|
||||
console.log(`\n--> Evaluate Transaction: ReadAssetPrivateDetails from ${collectionName}, ID: ${assetID}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -475,6 +475,68 @@ func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface)
|
|||
|
||||
}
|
||||
|
||||
// PurgeAsset can be used by the owner of the asset to delete the asset
|
||||
// Trigger removal of the asset
|
||||
func (s *SmartContract) PurgeAsset(ctx contractapi.TransactionContextInterface) error {
|
||||
|
||||
transientMap, err := ctx.GetStub().GetTransient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting transient: %v", err)
|
||||
}
|
||||
|
||||
// Asset properties are private, therefore they get passed in transient field
|
||||
transientDeleteJSON, ok := transientMap["asset_purge"]
|
||||
if !ok {
|
||||
return fmt.Errorf("asset to purge not found in the transient map")
|
||||
}
|
||||
|
||||
type assetPurge struct {
|
||||
ID string `json:"assetID"`
|
||||
}
|
||||
|
||||
var assetPurgeInput assetPurge
|
||||
err = json.Unmarshal(transientDeleteJSON, &assetPurgeInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal JSON: %v", err)
|
||||
}
|
||||
|
||||
if len(assetPurgeInput.ID) == 0 {
|
||||
return fmt.Errorf("assetID field must be a non-empty string")
|
||||
}
|
||||
|
||||
// Verify that the client is submitting request to peer in their organization
|
||||
err = verifyClientOrgMatchesPeerOrg(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("PurgeAsset cannot be performed: Error %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Purging Asset: %v", assetPurgeInput.ID)
|
||||
|
||||
// Note that there is no check here to see if the id exist; it might have been 'deleted' already
|
||||
// so a check here is pointless. We would need to call purge irrespective of the result
|
||||
// A delete can be called before purge, but is not essential
|
||||
|
||||
ownerCollection, err := getCollectionName(ctx) // Get owners collection
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to infer private collection name for the org: %v", err)
|
||||
}
|
||||
|
||||
// delete the asset from state
|
||||
err = ctx.GetStub().PurgePrivateData(assetCollection, assetPurgeInput.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to purge state from asset collection: %v", err)
|
||||
}
|
||||
|
||||
// Finally, delete private details of asset
|
||||
err = ctx.GetStub().PurgePrivateData(ownerCollection, assetPurgeInput.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to purge state from owner collection: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// DeleteTranferAgreement can be used by the buyer to withdraw a proposal from
|
||||
// the asset collection and from his own collection.
|
||||
func (s *SmartContract) DeleteTranferAgreement(ctx contractapi.TransactionContextInterface) error {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module github.com/hyperledger/fabric-samples/asset-transfer-private-data/chainco
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20220720122508-9207360bbddd
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20220920210243-7bc6fa0dd58b
|
||||
github.com/hyperledger/fabric-contract-api-go v1.2.0
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20220613214546-bf864f01d75e
|
||||
github.com/stretchr/testify v1.8.0
|
||||
|
|
|
|||
|
|
@ -165,6 +165,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
|||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20220720122508-9207360bbddd h1:AIa0b7UPrt8e1YN4/68vhNnPxy/Mrgq9d2bYJ6O/KTE=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20220720122508-9207360bbddd/go.mod h1:OxME3M0bbgoWYHpXIVMzpbXgFqrTZnFmlH0Cpml54m0=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20220920210243-7bc6fa0dd58b h1:MGT5rdajc4zbsbU7yMzkLJmsiRwJk5gBX5OdpU117Bg=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20220920210243-7bc6fa0dd58b/go.mod h1:OxME3M0bbgoWYHpXIVMzpbXgFqrTZnFmlH0Cpml54m0=
|
||||
github.com/hyperledger/fabric-contract-api-go v1.2.0 h1:BmArPRmTjiC2brHk2FNlDoJ8bOI0ExKZhj2YqWAiv5o=
|
||||
github.com/hyperledger/fabric-contract-api-go v1.2.0/go.mod h1:GU2NV95E5LNkFTCL3xcPgXzi8QNLXBZhx7DGnKskuqw=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20220613214546-bf864f01d75e h1:Ae2p0e+v5ekrl4KgkbCStBTSoV67Cg9fPkEWrv0f3nk=
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ version '1.0-SNAPSHOT'
|
|||
|
||||
dependencies {
|
||||
|
||||
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
|
||||
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+'
|
||||
implementation 'org.json:json:+'
|
||||
|
||||
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
|
||||
|
|
|
|||
|
|
@ -488,6 +488,9 @@ public final class AssetTransfer implements ContractInterface {
|
|||
* Deletes a asset & related details from the ledger.
|
||||
* Input in transient map: asset_delete
|
||||
*
|
||||
* This deletes the private data, but does not trigger an immediate cleanup
|
||||
* of the history. To specifically force removal right now use purge
|
||||
*
|
||||
* @param ctx the transaction context
|
||||
*/
|
||||
@Transaction(intent = Transaction.TYPE.SUBMIT)
|
||||
|
|
@ -539,6 +542,53 @@ public final class AssetTransfer implements ContractInterface {
|
|||
stub.delPrivateData(ownersCollectionName, assetID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the history of the asset from Private Data
|
||||
* (delete does not need to be called as well)
|
||||
* Input in transient map: asset_delete
|
||||
*
|
||||
* @param ctx the transaction context
|
||||
*/
|
||||
@Transaction(intent = Transaction.TYPE.SUBMIT)
|
||||
public void PurgeAsset(final Context ctx) {
|
||||
ChaincodeStub stub = ctx.getStub();
|
||||
Map<String, byte[]> transientMap = ctx.getStub().getTransient();
|
||||
if (!transientMap.containsKey("asset_purge")) {
|
||||
String errorMessage = String.format("PurgeAsset call must specify 'asset_purge' in Transient map input");
|
||||
System.err.println(errorMessage);
|
||||
throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString());
|
||||
}
|
||||
|
||||
byte[] transientAssetJSON = transientMap.get("asset_purge");
|
||||
final String assetID;
|
||||
|
||||
try {
|
||||
JSONObject json = new JSONObject(new String(transientAssetJSON, UTF_8));
|
||||
assetID = json.getString("assetID");
|
||||
|
||||
} catch (Exception err) {
|
||||
String errorMessage = String.format("TransientMap deserialized error: %s ", err);
|
||||
System.err.println(errorMessage);
|
||||
throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString());
|
||||
}
|
||||
|
||||
// Note that there is no check here to see if the id exist; it might have been 'deleted' already
|
||||
// so a check here is pointless. We would need to call purge irrespective of the result
|
||||
// A delete can be called before purge, but is not essential
|
||||
|
||||
String ownersCollectionName = getCollectionName(ctx);
|
||||
verifyClientOrgMatchesPeerOrg(ctx);
|
||||
|
||||
// delete the key from asset collection
|
||||
System.out.printf("PurgeAsset: collection %s, ID %s\n", ASSET_COLLECTION_NAME, assetID);
|
||||
stub.purgePrivateData(ASSET_COLLECTION_NAME, assetID);
|
||||
|
||||
// Finally, delete private details of asset
|
||||
System.out.printf("PurgeAsset: collection %s, ID %s\n", ownersCollectionName, assetID);
|
||||
stub.purgePrivateData(ownersCollectionName, assetID);
|
||||
}
|
||||
|
||||
|
||||
// Used by TransferAsset to verify that the transfer is being initiated by the owner and that
|
||||
// the buyer has agreed to the same appraisal value as the owner
|
||||
private void verifyAgreement(final Context ctx, final String assetID, final String owner, final String buyerMSP) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ function print() {
|
|||
echo -e "${GREEN}${1}${NC}"
|
||||
}
|
||||
|
||||
dirs=("$(find . -name "*-java" -type d -not -path '*/.*')")
|
||||
# remove the java asset-private-data until the publishing issues have been resolved
|
||||
dirs=("$(find . -name "*-java" -type d -not -path '*/.*' -not -path '*/asset-transfer-private-data/*')")
|
||||
for dir in $dirs; do
|
||||
print "Linting $dir"
|
||||
pushd $dir
|
||||
|
|
|
|||
|
|
@ -269,13 +269,11 @@ Capabilities:
|
|||
# used with prior release orderers.
|
||||
# Set the value of the capability to true to require it.
|
||||
Application: &ApplicationCapabilities
|
||||
# V2_0 application capability ensures that peers behave according
|
||||
# to v2.0 application capabilities. Peers from
|
||||
# prior releases would behave in an incompatible way, and are therefore
|
||||
# not able to participate in channels at v2.0 application capability.
|
||||
# Prior to enabling V2.0 application capabilities, ensure that all
|
||||
# peers on channel are at v2.0.0 or later.
|
||||
V2_0: true
|
||||
# V2.5 for Application enables the new non-backwards compatible
|
||||
# features of fabric v2.5, namely the ability to purge private data.
|
||||
# Prior to enabling V2.5 application capabilities, ensure that all
|
||||
# peers on a channel are at v2.5.0 or later.
|
||||
V2_5: true
|
||||
|
||||
################################################################################
|
||||
#
|
||||
|
|
|
|||
|
|
@ -163,13 +163,11 @@ Capabilities:
|
|||
# used with prior release orderers.
|
||||
# Set the value of the capability to true to require it.
|
||||
Application: &ApplicationCapabilities
|
||||
# V2_0 application capability ensures that peers behave according
|
||||
# to v2.0 application capabilities. Peers from
|
||||
# prior releases would behave in an incompatible way, and are therefore
|
||||
# not able to participate in channels at v2.0 application capability.
|
||||
# Prior to enabling V2.0 application capabilities, ensure that all
|
||||
# peers on channel are at v2.0.0 or later.
|
||||
V2_0: true
|
||||
# V2.5 for Application enables the new non-backwards compatible
|
||||
# features of fabric v2.5, namely the ability to purge private data.
|
||||
# Prior to enabling V2.5 application capabilities, ensure that all
|
||||
# peers on a channel are at v2.5.0 or later.
|
||||
V2_5: true
|
||||
|
||||
################################################################################
|
||||
#
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ Capabilities:
|
|||
# Prior to enabling V2.0 channel capabilities, ensure that all
|
||||
# orderers and peers on a channel are at v2.0.0 or later.
|
||||
V2_0: true
|
||||
|
||||
|
||||
# Orderer capabilities apply only to the orderers, and may be safely
|
||||
# used with prior release peers.
|
||||
|
|
@ -146,13 +147,11 @@ Capabilities:
|
|||
# used with prior release orderers.
|
||||
# Set the value of the capability to true to require it.
|
||||
Application: &ApplicationCapabilities
|
||||
# V2_0 application capability ensures that peers behave according
|
||||
# to v2.0 application capabilities. Peers from
|
||||
# prior releases would behave in an incompatible way, and are therefore
|
||||
# not able to participate in channels at v2.0 application capability.
|
||||
# Prior to enabling V2.0 application capabilities, ensure that all
|
||||
# peers on channel are at v2.0.0 or later.
|
||||
V2_0: true
|
||||
# V2.5 for Application enables the new non-backwards compatible
|
||||
# features of fabric v2.5, namely the ability to purge private data.
|
||||
# Prior to enabling V2.5 application capabilities, ensure that all
|
||||
# peers on a channel are at v2.5.0 or later.
|
||||
V2_5: true
|
||||
|
||||
################################################################################
|
||||
#
|
||||
|
|
|
|||
Loading…
Reference in a new issue