mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 07:25:10 +00:00
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:
parent
9df7e9f86d
commit
72559dfbb5
8 changed files with 56 additions and 37 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue