From 72559dfbb51c8b2936a4a796accc656c19f41493 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 10 Dec 2021 08:51:21 +0000 Subject: [PATCH] More Gateway asset-transfer-basic tweaks to support docs (#556) Signed-off-by: Mark S. Lewis --- .../application-gateway-typescript/src/app.ts | 21 +++++++------ .../chaincode-external/assetTransfer.go | 31 ++++++++++++------- .../chaincode-go/chaincode/smartcontract.go | 17 +++++++--- .../chaincode/smartcontract_test.go | 4 +-- .../samples/assettransfer/AssetTransfer.java | 6 ++-- .../assettransfer/AssetTransferTest.java | 4 +-- .../chaincode-javascript/lib/assetTransfer.js | 4 ++- .../chaincode-typescript/src/assetTransfer.ts | 6 ++-- 8 files changed, 56 insertions(+), 37 deletions(-) diff --git a/asset-transfer-basic/application-gateway-typescript/src/app.ts b/asset-transfer-basic/application-gateway-typescript/src/app.ts index c13ec871..352be263 100644 --- a/asset-transfer-basic/application-gateway-typescript/src/app.ts +++ b/asset-transfer-basic/application-gateway-typescript/src/app.ts @@ -31,6 +31,7 @@ const tlsCertPath = path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', const peerEndpoint = 'localhost:7051'; const utf8Decoder = new TextDecoder(); +const assetId = `asset${Date.now()}`; async function main(): Promise { // The gRPC client connection should be shared by all Gateway connections to this endpoint. @@ -59,7 +60,7 @@ async function main(): Promise { await createAsset(contract); // Update an existing asset asynchronously. - await updateAssetAsync(contract); + await transferAssetAsync(contract); // Get the asset details by assetID. await readAssetByID(contract); @@ -124,9 +125,8 @@ async function getAllAssets(contract: Contract): Promise { * Submit a transaction synchronously, blocking until it has been committed to the ledger. */ async function createAsset(contract: Contract): Promise { - console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments'); + console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments'); - const assetId = `asset${Date.now()}`; await contract.submitTransaction( 'CreateAsset', assetId, @@ -143,14 +143,15 @@ async function createAsset(contract: Contract): Promise { * Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI) * while waiting for the commit notification. */ -async function updateAssetAsync(contract: Contract): Promise { - console.log('\n--> Async Submit Transaction: UpdateAsset, updates existing asset with ID, color, owner, size, and appraisedValue arguments'); +async function transferAssetAsync(contract: Contract): Promise { + console.log('\n--> Async Submit Transaction: TransferAsset, updates existing asset owner'); - const commit = await contract.submitAsync('UpdateAsset', { - arguments: ['asset1', 'blue', '5', 'Tomoko', '400'], + const commit = await contract.submitAsync('TransferAsset', { + arguments: [assetId, 'Saptha'], }); + const oldOwner = utf8Decoder.decode(commit.getResult()); - console.log('*** Transaction submitted successfully'); + console.log(`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`); console.log('*** Waiting for transaction commit'); const status = await commit.getStatus(); @@ -162,9 +163,9 @@ async function updateAssetAsync(contract: Contract): Promise { } async function readAssetByID(contract: Contract): Promise { - console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes'); + console.log('\n--> Evaluate Transaction: ReadAsset, function returns asset attributes'); - const resultBytes = await contract.evaluateTransaction('ReadAsset', 'asset1'); + const resultBytes = await contract.evaluateTransaction('ReadAsset', assetId); const resultJson = utf8Decoder.decode(resultBytes); const result = JSON.parse(resultJson); diff --git a/asset-transfer-basic/chaincode-external/assetTransfer.go b/asset-transfer-basic/chaincode-external/assetTransfer.go index ab2b8ecd..a136975f 100644 --- a/asset-transfer-basic/chaincode-external/assetTransfer.go +++ b/asset-transfer-basic/chaincode-external/assetTransfer.go @@ -161,20 +161,27 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, return assetJSON != nil, nil } -// TransferAsset updates the owner field of asset with given id in world state. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { +// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. +func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { asset, err := s.ReadAsset(ctx, id) if err != nil { - return err + return "", err } + oldOwner := asset.Owner asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) if err != nil { - return err + return "", err } - return ctx.GetStub().PutState(id, assetJSON) + err = ctx.GetStub().PutState(id, assetJSON) + if err != nil { + return "", err + } + + return oldOwner, nil } // GetAllAssets returns all assets found in world state @@ -223,9 +230,9 @@ func main() { } server := &shim.ChaincodeServer{ - CCID: config.CCID, - Address: config.Address, - CC: chaincode, + CCID: config.CCID, + Address: config.Address, + CC: chaincode, TLSProps: getTLSProperties(), } @@ -265,9 +272,9 @@ func getTLSProperties() shim.TLSProperties { } return shim.TLSProperties{ - Disabled: tlsDisabled, - Key: keyBytes, - Cert: certBytes, + Disabled: tlsDisabled, + Key: keyBytes, + Cert: certBytes, ClientCACerts: clientCACertBytes, } } @@ -284,7 +291,7 @@ func getEnvOrDefault(env, defaultVal string) string { // cannot be parsed! func getBoolOrDefault(value string, defaultVal bool) bool { parsed, err := strconv.ParseBool(value) - if err!= nil { + if err != nil { return defaultVal } return parsed diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go index 7373ad42..55bc24d9 100644 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go @@ -142,20 +142,27 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, return assetJSON != nil, nil } -// TransferAsset updates the owner field of asset with given id in world state. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { +// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. +func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { asset, err := s.ReadAsset(ctx, id) if err != nil { - return err + return "", err } + oldOwner := asset.Owner asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) if err != nil { - return err + return "", err } - return ctx.GetStub().PutState(id, assetJSON) + err = ctx.GetStub().PutState(id, assetJSON) + if err != nil { + return "", err + } + + return oldOwner, nil } // GetAllAssets returns all assets found in world state diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go index cb001ded..b2ddb2fc 100644 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go @@ -143,11 +143,11 @@ func TestTransferAsset(t *testing.T) { chaincodeStub.GetStateReturns(bytes, nil) assetTransfer := chaincode.SmartContract{} - err = assetTransfer.TransferAsset(transactionContext, "", "") + _, err = assetTransfer.TransferAsset(transactionContext, "", "") require.NoError(t, err) chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = assetTransfer.TransferAsset(transactionContext, "", "") + _, err = assetTransfer.TransferAsset(transactionContext, "", "") require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") } diff --git a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java index fa7aba67..ac625b84 100644 --- a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java +++ b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java @@ -185,10 +185,10 @@ public final class AssetTransfer implements ContractInterface { * @param ctx the transaction context * @param assetID the ID of the asset being transferred * @param newOwner the new owner - * @return the updated asset + * @return the old owner */ @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset TransferAsset(final Context ctx, final String assetID, final String newOwner) { + public String TransferAsset(final Context ctx, final String assetID, final String newOwner) { ChaincodeStub stub = ctx.getStub(); String assetJSON = stub.getStringState(assetID); @@ -205,7 +205,7 @@ public final class AssetTransfer implements ContractInterface { String sortedJson = genson.serialize(newAsset); stub.putStringState(assetID, sortedJson); - return newAsset; + return asset.getOwner(); } /** diff --git a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java b/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java index cbbb172f..520bcec4 100644 --- a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java +++ b/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java @@ -224,9 +224,9 @@ public final class AssetTransferTest { when(stub.getStringState("asset1")) .thenReturn("{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"Tomoko\", \"appraisedValue\": 300 }"); - Asset asset = contract.TransferAsset(ctx, "asset1", "Dr Evil"); + String oldOwner = contract.TransferAsset(ctx, "asset1", "Dr Evil"); - assertThat(asset).isEqualTo(new Asset("asset1", "blue", 5, "Dr Evil", 300)); + assertThat(oldOwner).isEqualTo("Tomoko"); } @Test diff --git a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js index 22d109c8..beb87239 100644 --- a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js +++ b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js @@ -135,9 +135,11 @@ class AssetTransfer extends Contract { async TransferAsset(ctx, id, newOwner) { const assetString = await this.ReadAsset(ctx, id); const asset = JSON.parse(assetString); + const oldOwner = asset.Owner; asset.Owner = newOwner; // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); + ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); + return oldOwner; } // GetAllAssets returns all assets found in the world state. diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts index 586c4758..b9b6c3ff 100644 --- a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts +++ b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts @@ -135,14 +135,16 @@ export class AssetTransferContract extends Contract { return assetJSON && assetJSON.length > 0; } - // TransferAsset updates the owner field of asset with given id in the world state. + // TransferAsset updates the owner field of asset with given id in the world state, and returns the old owner. @Transaction() - public async TransferAsset(ctx: Context, id: string, newOwner: string): Promise { + public async TransferAsset(ctx: Context, id: string, newOwner: string): Promise { const assetString = await this.ReadAsset(ctx, id); const asset = JSON.parse(assetString); + const oldOwner = asset.Owner; asset.Owner = newOwner; // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); + return oldOwner; } // GetAllAssets returns all assets found in the world state.