Skip to content

Commit

Permalink
Add deleteRecursive transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurPaivaT committed Mar 26, 2021
1 parent 4533047 commit 3537da6
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
86 changes: 86 additions & 0 deletions assets/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package assets

import (
"encoding/json"
"strings"

"github.com/goledgerdev/cc-tools/errors"
"github.com/hyperledger/fabric/core/chaincode/shim"
Expand Down Expand Up @@ -59,3 +60,88 @@ func (a *Asset) Delete(stub shim.ChaincodeStubInterface) ([]byte, error) {

return assetJSON, nil
}

// DeleteRecursive erases asset and recursively erases those which reference it
func (a *Asset) DeleteRecursive(stub shim.ChaincodeStubInterface) ([]byte, error) {
var err error

// Check if org has write permission
err = a.CheckWriters(stub)
if err != nil {
return nil, errors.WrapError(err, "failed write permission check")
}

err = deleteRecursive(stub, a.Key())
if err != nil {
return nil, errors.WrapError(err, "error deleting asset Recursively")
}

response := map[string]interface{}{
"deletedKeys": deletedKeys,
}
responseJSON, err := json.Marshal(response)
if err != nil {
return nil, errors.WrapError(err, "failed to marshal response")
}

return responseJSON, nil
}

var deletedKeys []string

func deleteRecursive(stub shim.ChaincodeStubInterface, key string) error {
deletedKeys = append(deletedKeys, key)
queryIt, err := stub.GetStateByPartialCompositeKey(key, []string{})
if err != nil {
return errors.WrapErrorWithStatus(err, "failed to check reference index", 500)
}
defer queryIt.Close()

for queryIt.HasNext() {
next, _ := queryIt.Next()
referrerKeyString := strings.ReplaceAll(next.Key, key, "")
referrerKeyString = strings.ReplaceAll(referrerKeyString, "\x00", "")
var isDeleted bool

for _, deletedKey := range deletedKeys {
if deletedKey == referrerKeyString {
isDeleted = true
break
}
}
if !isDeleted {
err = deleteRecursive(stub, referrerKeyString)
if err != nil {
return errors.WrapError(err, "error deleting referrer asset:")
}
}
}

keyMap := make(map[string]interface{})
keyMap["@key"] = key
assetKey, err := NewKey(keyMap)

asset, err := assetKey.Get(stub)
if err != nil {
return errors.WrapError(err, "failed to read asset from blockchain")
}
// Clean up reference markers for this asset
err = asset.delRefs(stub)
if err != nil {
return errors.WrapError(err, "failed cleaning reference index")
}

if !asset.IsPrivate() {
err = stub.DelState(asset.Key())
if err != nil {
return errors.WrapError(err, "failed to delete state from ledger")
}
} else {
err = stub.DelPrivateData(asset.TypeTag(), asset.Key())
if err != nil {
return errors.WrapError(err, "failed to delete state from private collection")
}
}

return nil
}
3 changes: 3 additions & 0 deletions assets/references.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ func (a Asset) delRefs(stub shim.ChaincodeStubInterface) errors.ICCError {
for _, referencedKey := range refKeys {
// Construct reference key
indexKey, err := stub.CreateCompositeKey(referencedKey.Key(), []string{assetKey})
if err != nil {
return errors.WrapErrorWithStatus(err, "could not create composite key", 400)
}
// Check if asset exists in blockchain
err = stub.DelState(indexKey)
if err != nil {
Expand Down
37 changes: 37 additions & 0 deletions transactions/deleteAsset.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,40 @@ var DeleteAsset = Transaction{
return response, nil
},
}

// DeleteRecursive deletes an asset and it's recursive referrers from the blockchain
var DeleteRecursive = Transaction{
Tag: "deleteAssetRecursive",
Label: "Delete Asset",
Method: "DELETE",
Description: "",

MetaTx: true,
Args: []Argument{
{
Tag: "key",
Description: "Key of the asset to be deleted.",
DataType: "@key",
Required: true,
},
},
Routine: func(stub shim.ChaincodeStubInterface, req map[string]interface{}) ([]byte, errors.ICCError) {
// This is safe to do because validation is done before calling routine
key := req["key"].(assets.Key)

var err error

// Fetch asset from blockchain
asset, err := key.Get(stub)
if err != nil {
return nil, errors.WrapError(err, "failed to read asset from blockchain")
}

response, err := asset.DeleteRecursive(stub)
if err != nil {
return nil, errors.WrapError(err, "failed to delete asset recursively")
}

return response, nil
},
}
1 change: 1 addition & 0 deletions transactions/txList.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var basicTxs = []Transaction{
Search,
UpdateAsset,
DeleteAsset,
DeleteRecursive,
}

// TxList returns a copy of the txList variable
Expand Down

0 comments on commit 3537da6

Please sign in to comment.