More Gateway asset-transfer-basic tweaks to support docs (#556)

Signed-off-by: Mark S. Lewis <mark_lewis@uk.ibm.com>
This commit is contained in:
Mark S. Lewis 2021-12-10 08:51:21 +00:00 committed by GitHub
parent 9df7e9f86d
commit 72559dfbb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 37 deletions

View file

@ -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<void> {
// The gRPC client connection should be shared by all Gateway connections to this endpoint.
@ -59,7 +60,7 @@ async function main(): Promise<void> {
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<void> {
* Submit a transaction synchronously, blocking until it has been committed to the ledger.
*/
async function createAsset(contract: Contract): Promise<void> {
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<void> {
* 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<void> {
console.log('\n--> Async Submit Transaction: UpdateAsset, updates existing asset with ID, color, owner, size, and appraisedValue arguments');
async function transferAssetAsync(contract: Contract): Promise<void> {
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<void> {
}
async function readAssetByID(contract: Contract): Promise<void> {
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);

View file

@ -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

View file

@ -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

View file

@ -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")
}

View file

@ -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();
}
/**

View file

@ -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

View file

@ -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.

View file

@ -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<void> {
public async TransferAsset(ctx: Context, id: string, newOwner: string): Promise<string> {
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.