Skip to content

Commit

Permalink
Merge pull request #45 from VRamakrishna/main
Browse files Browse the repository at this point in the history
Fabric Interop Node SDK Support for HTLC-based Asset Exchanges
  • Loading branch information
VRamakrishna authored May 18, 2021
2 parents 5e2dbc8 + aa0cb2c commit 23316ab
Show file tree
Hide file tree
Showing 10 changed files with 1,459 additions and 158 deletions.
18 changes: 16 additions & 2 deletions common/interop-protos/common/asset_locks.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ message AssetClaim {
}

message AssetLockHTLC {
bytes hash = 1;
bytes hashBase64 = 1;
uint64 expiryTimeSecs = 2;
enum TimeSpec {
EPOCH = 0;
Expand All @@ -28,7 +28,7 @@ message AssetLockHTLC {
}

message AssetClaimHTLC {
bytes hashPreimage = 1;
bytes hashPreimageBase64 = 1;
}

message AssetExchangeAgreement {
Expand All @@ -44,3 +44,17 @@ message FungibleAssetExchangeAgreement {
string locker = 3;
string recipient = 4;
}

message AssetContractHTLC {
string contractId = 1;
AssetExchangeAgreement agreement = 2;
AssetLockHTLC lock = 3;
AssetClaimHTLC claim = 4;
}

message FungibleAssetContractHTLC {
string contractId = 1;
FungibleAssetExchangeAgreement agreement = 2;
AssetLockHTLC lock = 3;
AssetClaimHTLC claim = 4;
}
81 changes: 39 additions & 42 deletions core/network/fabric-interop-cc/contracts/interop/manage_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ const(
contractIdPrefix = "ContractId_" // prefix for the map, contractId --> asset-key
)

// helper functions to log and return errors
func logThenErrorf(format string, args ...interface{}) error {
errorMsg := fmt.Sprintf(format, args...)
log.Error(errorMsg)
return errors.New(errorMsg)
}

// function to generate a "SHA256" hash in base64 format for a given preimage
func generateSHA256HashInBase64Form(preimage string) string {
hasher := sha256.New()
Expand All @@ -68,9 +75,7 @@ func generateContractIdMapKey(contractId string) string {
func generateAssetLockKeyAndContractId(ctx contractapi.TransactionContextInterface, assetAgreement *common.AssetExchangeAgreement) (string, string, error) {
assetLockKey, err := ctx.GetStub().CreateCompositeKey("AssetExchangeContract", []string{assetAgreement.Type, assetAgreement.Id})
if err != nil {
errorMsg := fmt.Sprintf("error while creating composite key: %+v", err)
log.Error(errorMsg)
return "", "", errors.New(errorMsg)
return "", "", logThenErrorf("error while creating composite key: %+v", err)
}

contractId := generateSHA256HashInBase64Form(assetLockKey)
Expand Down Expand Up @@ -98,7 +103,7 @@ func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, a
return "", err
}
//display the requested asset agreement
log.Info(fmt.Sprintf("assetExchangeAgreement: %+v\n", assetAgreement))
log.Infof("assetExchangeAgreement: %+v\n", assetAgreement)

lockInfoHTLC := &common.AssetLockHTLC{}
err = proto.Unmarshal([]byte(lockInfoBytes), lockInfoHTLC)
Expand All @@ -107,12 +112,10 @@ func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, a
return "", err
}
//display the passed lock information
log.Info(fmt.Sprintf("lockInfoHTLC: %+v\n", lockInfoHTLC))
log.Infof("lockInfoHTLC: %+v\n", lockInfoHTLC)

if lockInfoHTLC.TimeSpec != common.AssetLockHTLC_EPOCH {
errorMsg := "only EPOCH time is supported at present"
log.Error(errorMsg)
return "", errors.New(errorMsg)
return "", logThenErrorf("only EPOCH time is supported at present")
}

assetLockKey, contractId, err := generateAssetLockKeyAndContractId(ctx, assetAgreement)
Expand All @@ -121,7 +124,7 @@ func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, a
return "", err
}

assetLockVal := AssetLockValue{Locker: assetAgreement.Locker, Recipient: assetAgreement.Recipient, Hash: string(lockInfoHTLC.Hash), ExpiryTimeSecs: lockInfoHTLC.ExpiryTimeSecs}
assetLockVal := AssetLockValue{Locker: assetAgreement.Locker, Recipient: assetAgreement.Recipient, Hash: string(lockInfoHTLC.HashBase64), ExpiryTimeSecs: lockInfoHTLC.ExpiryTimeSecs}

assetLockValBytes, err := ctx.GetStub().GetState(assetLockKey)
if err != nil {
Expand All @@ -130,16 +133,12 @@ func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, a
}

if assetLockValBytes != nil {
errorMsg := fmt.Sprintf("asset of type %s and ID %s is already locked", assetAgreement.Type, assetAgreement.Id)
log.Error(errorMsg)
return "", errors.New(errorMsg)
return "", logThenErrorf("asset of type %s and ID %s is already locked", assetAgreement.Type, assetAgreement.Id)
}

assetLockValBytes, err = json.Marshal(assetLockVal)
if err != nil {
errorMsg := fmt.Sprintf("marshal error: %s", err)
log.Error(errorMsg)
return "", errors.New(errorMsg)
return "", logThenErrorf("marshal error: %+v", err)
}

err = ctx.GetStub().PutState(assetLockKey, assetLockValBytes)
Expand All @@ -150,9 +149,7 @@ func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, a

assetLockKeyBytes, err := json.Marshal(assetLockKey)
if err != nil {
errorMsg := fmt.Sprintf("marshal error: %s", err)
log.Error(errorMsg)
return "", errors.New(errorMsg)
return "", logThenErrorf("marshal error: %+v", err)
}

err = ctx.GetStub().PutState(generateContractIdMapKey(string(contractId)), assetLockKeyBytes)
Expand All @@ -173,7 +170,7 @@ func (s *SmartContract) UnLockAsset(ctx contractapi.TransactionContextInterface,
return err
}
//display the requested asset agreement
log.Info(fmt.Sprintf("assetExchangeAgreement: %+v\n", assetAgreement))
log.Infof("assetExchangeAgreement: %+v\n", assetAgreement)

assetLockKey, _, err := generateAssetLockKeyAndContractId(ctx, assetAgreement)
if err != nil {
Expand All @@ -187,7 +184,7 @@ func (s *SmartContract) UnLockAsset(ctx contractapi.TransactionContextInterface,
return err
}

if assetLockValBytes == nil {
if assetLockValBytes == nil {
errorMsg := fmt.Sprintf("no asset of type %s and ID %s is locked", assetAgreement.Type, assetAgreement.Id)
log.Error(errorMsg)
return errors.New(errorMsg)
Expand All @@ -209,7 +206,7 @@ func (s *SmartContract) UnLockAsset(ctx contractapi.TransactionContextInterface,

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) < assetLockVal.ExpiryTimeSecs {
if currentTimeSecs < assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("cannot unlock asset of type %s and ID %s as the expiry time is not yet elapsed", assetAgreement.Type, assetAgreement.Id)
log.Error(errorMsg)
return errors.New(errorMsg)
Expand All @@ -235,7 +232,7 @@ func (s *SmartContract) IsAssetLocked(ctx contractapi.TransactionContextInterfac
return false, err
}
//display the requested asset agreement
log.Info(fmt.Sprintf("assetExchangeAgreement: %+v\n", assetAgreement))
log.Infof("assetExchangeAgreement: %+v\n", assetAgreement)

assetLockKey, _, err := generateAssetLockKeyAndContractId(ctx, assetAgreement)
if err != nil {
Expand All @@ -262,11 +259,11 @@ func (s *SmartContract) IsAssetLocked(ctx contractapi.TransactionContextInterfac
log.Error(errorMsg)
return false, errors.New(errorMsg)
}
log.Info(fmt.Sprintf("assetLockVal: %+v\n", assetLockVal))
log.Infof("assetLockVal: %+v\n", assetLockVal)

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) >= assetLockVal.ExpiryTimeSecs {
if currentTimeSecs >= assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("expiry time for asset of type %s and ID %s is already elapsed", assetAgreement.Type, assetAgreement.Id)
log.Error(errorMsg)
return false, errors.New(errorMsg)
Expand Down Expand Up @@ -307,9 +304,9 @@ func checkIfCorrectPreimage(preimageBase64 string, hashBase64 string) (bool, err

shaHashBase64 := generateSHA256HashInBase64Form(string(preimage))
if shaHashBase64 == hashBase64 {
log.Info(fmt.Sprintf("%s: preimage %s is passed correctly.\n", funName, preimage))
log.Infof("%s: preimage %s is passed correctly.\n", funName, preimage)
} else {
log.Info(fmt.Sprintf("%s: preimage %s is not passed correctly.\n", funName, preimage))
log.Infof("%s: preimage %s is not passed correctly.\n", funName, preimage)
return false, nil
}
return true, nil
Expand All @@ -325,7 +322,7 @@ func (s *SmartContract) ClaimAsset(ctx contractapi.TransactionContextInterface,
return err
}
// display the requested asset agreement
log.Info(fmt.Sprintf("assetExchangeAgreement: %+v\n", assetAgreement))
log.Infof("assetExchangeAgreement: %+v\n", assetAgreement)

claimInfo := &common.AssetClaimHTLC{}
err = proto.Unmarshal([]byte(claimInfoBytes), claimInfo)
Expand All @@ -336,7 +333,7 @@ func (s *SmartContract) ClaimAsset(ctx contractapi.TransactionContextInterface,
}

// display the claim information
log.Info(fmt.Sprintf("claimInfo: %+v\n", claimInfo))
log.Infof("claimInfo: %+v\n", claimInfo)

assetLockKey, _, err := generateAssetLockKeyAndContractId(ctx, assetAgreement)
if err != nil {
Expand Down Expand Up @@ -372,14 +369,14 @@ func (s *SmartContract) ClaimAsset(ctx contractapi.TransactionContextInterface,

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) >= assetLockVal.ExpiryTimeSecs {
if currentTimeSecs >= assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("cannot claim asset of type %s and ID %s as the expiry time is already elapsed", assetAgreement.Type, assetAgreement.Id)
log.Error(errorMsg)
return errors.New(errorMsg)
}

// compute the hash from the preimage
isCorrectPreimage, err := checkIfCorrectPreimage(string(claimInfo.HashPreimage), string(assetLockVal.Hash))
isCorrectPreimage, err := checkIfCorrectPreimage(string(claimInfo.HashPreimageBase64), string(assetLockVal.Hash))
if err != nil {
errorMsg := fmt.Sprintf("claim asset of type %s and ID %s error: %v", assetAgreement.Type, assetAgreement.Id, err)
log.Error(errorMsg)
Expand Down Expand Up @@ -452,7 +449,7 @@ func (s *SmartContract) UnLockAssetUsingContractId(ctx contractapi.TransactionCo

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) < assetLockVal.ExpiryTimeSecs {
if currentTimeSecs < assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("cannot unlock asset associated with the contractId %s as the expiry time is not yet elapsed", contractId)
log.Error(errorMsg)
return errors.New(errorMsg)
Expand Down Expand Up @@ -493,18 +490,18 @@ func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionCon
}

// display the claim information
log.Info(fmt.Sprintf("claimInfo: %+v\n", claimInfo))
log.Infof("claimInfo: %+v\n", claimInfo)

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) >= assetLockVal.ExpiryTimeSecs {
if currentTimeSecs >= assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("cannot claim asset associated with contractId %s as the expiry time is already elapsed", contractId)
log.Error(errorMsg)
return errors.New(errorMsg)
}

// compute the hash from the preimage
isCorrectPreimage, err := checkIfCorrectPreimage(string(claimInfo.HashPreimage), string(assetLockVal.Hash))
isCorrectPreimage, err := checkIfCorrectPreimage(string(claimInfo.HashPreimageBase64), string(assetLockVal.Hash))
if err != nil {
errorMsg := fmt.Sprintf("claim asset associated with contractId %s failed with error: %v", contractId, err)
log.Error(errorMsg)
Expand Down Expand Up @@ -545,7 +542,7 @@ func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.Transa

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) >= assetLockVal.ExpiryTimeSecs {
if currentTimeSecs >= assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("expiry time for asset associated with contractId %s is already elapsed", contractId)
log.Error(errorMsg)
return false, errors.New(errorMsg)
Expand Down Expand Up @@ -577,7 +574,7 @@ func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInte
}

//display the passed lock information
log.Info(fmt.Sprintf("lockInfoHTLC: %+v\n", lockInfoHTLC))
log.Infof("lockInfoHTLC: %+v\n", lockInfoHTLC)

if lockInfoHTLC.TimeSpec != common.AssetLockHTLC_EPOCH {
errorMsg := "only EPOCH time is supported at present"
Expand All @@ -589,7 +586,7 @@ func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInte
contractId := generateFungibleAssetLockContractId(ctx, assetAgreement)

assetLockVal := FungibleAssetLockValue{Type: assetAgreement.Type, NumUnits: assetAgreement.NumUnits, Locker: assetAgreement.Locker,
Recipient: assetAgreement.Recipient, Hash: string(lockInfoHTLC.Hash), ExpiryTimeSecs: lockInfoHTLC.ExpiryTimeSecs}
Recipient: assetAgreement.Recipient, Hash: string(lockInfoHTLC.HashBase64), ExpiryTimeSecs: lockInfoHTLC.ExpiryTimeSecs}

assetLockValBytes, err := ctx.GetStub().GetState(contractId)
if err != nil {
Expand Down Expand Up @@ -660,7 +657,7 @@ func (s *SmartContract) IsFungibleAssetLocked(ctx contractapi.TransactionContext

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) >= assetLockVal.ExpiryTimeSecs {
if currentTimeSecs >= assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("expiry time for fungible asset associated with contractId %s is already elapsed", contractId)
log.Error(errorMsg)
return false, errors.New(errorMsg)
Expand All @@ -687,18 +684,18 @@ func (s *SmartContract) ClaimFungibleAsset(ctx contractapi.TransactionContextInt
}

// display the claim information
log.Info(fmt.Sprintf("claimInfo: %+v\n", claimInfo))
log.Infof("claimInfo: %+v\n", claimInfo)

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) >= assetLockVal.ExpiryTimeSecs {
if currentTimeSecs >= assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("cannot claim fungible asset associated with contractId %s as the expiry time is already elapsed", contractId)
log.Error(errorMsg)
return errors.New(errorMsg)
}

// compute the hash from the preimage
isCorrectPreimage, err := checkIfCorrectPreimage(string(claimInfo.HashPreimage), string(assetLockVal.Hash))
isCorrectPreimage, err := checkIfCorrectPreimage(string(claimInfo.HashPreimageBase64), string(assetLockVal.Hash))
if err != nil {
errorMsg := fmt.Sprintf("claim fungible asset associated with contractId %s failed with error: %v", contractId, err)
log.Error(errorMsg)
Expand Down Expand Up @@ -732,7 +729,7 @@ func (s *SmartContract) UnLockFungibleAsset(ctx contractapi.TransactionContextIn

// Check if expiry time is elapsed
currentTimeSecs := uint64(time.Now().Unix())
if uint64(currentTimeSecs) < assetLockVal.ExpiryTimeSecs {
if currentTimeSecs < assetLockVal.ExpiryTimeSecs {
errorMsg := fmt.Sprintf("cannot unlock fungible asset associated with the contractId %s as the expiry time is not yet elapsed", contractId)
log.Error(errorMsg)
return errors.New(errorMsg)
Expand Down
Loading

0 comments on commit 23316ab

Please sign in to comment.