I am a beginner in hyperledger. My model.cto file has two transaction processor function one for transferring the car from manufacturer to the showroom and another one is for transferring the car from showroom to owner. model.cto file is given below,
namespace org.manufacturer.network
asset Car identified by carID {
o String carID
o String name
o String chasisNumber
--> Showroom showroom
--> Owner owner
}
participant Showroom identified by showroomID {
o String showroomID
o String name
}
participant Owner identified by ownerID {
o String ownerID
o String firstName
o String lastName
}
transaction Allocate {
--> Car car
--> Showroom newShowroom
}
transaction Purchase {
--> Showroom showroom
--> Owner newOwner
}
So, I want to add two functions in my script.js file, so that I could perform my transactions. My script.js file is given below
/**
* New script file
* #param {org.manufacturer.network.Allocate} allocate - allocating the car from manufacturer to showroom
* #param {org.manufacturer.network.Purchase} purchase - purchase the car by owner from showroom
* #transaction
*/
async function transferCar(allocate){
allocate.car.showroom = allocate.newShowroom;
let assetRegistry = await getAssetRegistry('org.manufacturer.network.Car');
await assetRegistry.update(allocate.car);
}
async function purchaseCar(purchase){
purchase.car.owner = purchase.newOwner;
let assetRegistry = await getAssetRegistry('org.manufacturer.network.Car');
await assetRegistry.update(purchase.car);
}
But the script file is giving error as Transaction processing function transferCar must have 1 function argument of type transaction.
How to add multiple transaction processor functions in a single script.js file?
Is that possible or I have to create two script.js file to handle the transactions?
That is not the correct way to define two transactions in the script.js file.
Your script.js file should be like this:
/**
* New script file
* #param {org.manufacturer.network.Allocate} allocate - allocating the car from manufacturer to showroom
* #transaction
*/
async function transferCar(allocate){
allocate.car.showroom = allocate.newShowroom;
let assetRegistry = await getAssetRegistry('org.manufacturer.network.Car');
await assetRegistry.update(allocate.car);
}
/**
* New script file
* #param {org.manufacturer.network.Purchase} purchase - purchase the car by owner from showroom
* #transaction
*/
async function purchaseCar(purchase){
purchase.car.owner = purchase.newOwner;
let assetRegistry = await getAssetRegistry('org.manufacturer.network.Car');
await assetRegistry.update(purchase.car);
}
This is how you can add more than one transaction in the script.js file.
I hope it will help you.
Related
I am making a blockchain application using hyperledger composer and have written my cto, with on transaction, and the script file with no visible errors. However, when i try submit a transaction it returns this error: Error: Could not find any transactions to execute for org.evidence.net.evidenceDeposit.
Here is my CTO file:
namespace org.evidence.net
enum type {
o storage
o device
o physical
}
enum status {
o collected
o stored
o withdrawn
}
asset EvidenceItem identified by evidenceItemId {
o String evidenceItemId
o String caseNo
o type Type
o status Status
o String optionalHash optional
--> person Holder
}
abstract participant person identified by id {
o String id
o String firstName
o String lastName
}
participant Investigator extends person {
}
participant EvidenceManager extends person {
}
participant FRT extends person {
}
transaction evidenceDeposit {
--> EvidenceItem EvidenceItem
--> EvidenceManager EvidenceManager
}
event FirstDeposit {
o String evidenceItemId
o String id
}
And here is my script file:
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Transfer evidence from FRT to Evidence Manager
* #param (org.evidence.net.evidenceDeposit} tx - the evidenceDeposit transaction
* #transaction
*/
const NS = 'org.evidence.net';
async function evidenceDeposit(tx) {
// get asset registry for evidenceItem
const evidenceItemRegistry = await getAssetRegistry(NS + '.evidenceItem');
//Get participant registry for Evidence Manager
const EvidenceManagerRegistry = await getParticipantRegistry(NS + '.EvidenceManager');
const evidenceItem = await evidenceItemRegistry.get(tx.evidenceItem.getIdentifier());
//Make sure that the evidenceItem exists
if (!evidenceItem) {
throw new Error(' Evidence with id ${tx.evidenceItem.getIdentifier()} does not exist');
exit();
}
if (evidenceItem.status !== 'collected') {
throw new Error('Evidence with id ${tx.evidenceItem.getIdentifier()} is not in collected status');
}
// Get Evidence Manager ID
const EvidenceManagerID = tx.EvidenceManager.getIdentifier();
//Make sure Evidence Manager exists
const EvidenceManager = await EvidenceManagerRegistry.get(EvidenceManagerID);
if(!EvidenceManager) {
throw new Error('Evidence Manager with id ${EvidenceManagerID} does not exist');
}
//Update evidenceItem with new owner
tx.evidenceItem.holder = tx.EvidenceManager;
tx.evidenceItem.status = 'stored';
//Update the asset in the asset registry
await evidenceItemRegistry.update(tx.evidenceItem);
//Create deposit event
let FirstDepositEvent = getFactory().newEvent(NS, 'FirstDeposit');
FirstDepositEvent.evidenceItemId = tx.evidenceItem.evidenceItemId;
FirstDepositEvent.id = tx.EvidenceManager.id;
// Emit the Event
emit(FirstDepositEvent);
}
I have looked around and can't seem to find the problem. Any help is appreciated.
Please see the readme below as Hyperledger Composer has been deprecated for over a year.
https://github.com/hyperledger/composer/blob/master/README.md
I have a little bit unusual problem. Following code works in online playground, but id doesn't work when i'm using generated API on rest server deployed locally. When trying to post transaction i get an error.
cto file:
namespace org.dps.track
asset Item identified by itemId{
o String itemId
o String name
o String idgId
o String serialNumber
o String comment
--> BU owner
--> Item [] items optional
}
participant BU identified by buId{
o String buId
o String name
o String country
o String city
}
participant Assembler extends BU{
}
participant Manufacturer extends BU{
}
transaction Trade{
--> Item item
--> BU newOwner
}
enum status{
o IN_TRANSIT
o DEPARTURED
o DELIVERED
}
chaincode:
/**
* Sample transaction processor function.
* #param {org.dps.track.Trade } trade - the sample transaction instance.
* #transaction
*/
async function tradeCommodity(trade) {
const factory = getFactory();
trade.item.owner = trade.newOwner;
var list = [];
if (trade.item.items && trade.item.items.length > 0) {
trade.item.items.forEach((asset) => {
list.push(asset);
});
}
const assetRegistry = await getAssetRegistry('org.dps.track.Item');
// persist the state of the current ITEM
await assetRegistry.update(trade.item);
for (var i = 0; i < list.length; ++i) {
let res = await assetRegistry.get(list[i].getIdentifier());
res.owner = factory.newRelationship('org.dps.track', 'Assembler', trade.newOwner.getIdentifier());
// persist the state of the ITEM with new owner as a relationship
await assetRegistry.update(res);
}
}
When trying to post transaction via Rest API i get error:
{
"error": {
"statusCode": 500,
"name": "Error",
"message": "Error trying invoke business network. Error: No valid responses from any peers.\nResponse from attempted peer comms was an error: Error: transaction returned with failure: Error: Could not find any functions to execute for transaction org.dps.track.Trade#e4764be8e037c7186774512860c0cde6d7eaed5c301ddf36c4c1ab560577861a",
"stack": "Error: Error trying invoke business network. Error: No valid responses from any peers.\nResponse from attempted peer comms was an error: Error: transaction returned with failure: Error: Could not find any functions to execute for transaction org.dps.track.Trade#e4764be8e037c7186774512860c0cde6d7eaed5c301ddf36c4c1ab560577861a\n at HLFConnection.invokeChainCode (/home/bryczek/.nvm/versions/node/v8.11.3/lib/node_modules/composer-rest-server/node_modules/composer-connector-hlfv1/lib/hlfconnection.js:1002:30)\n at <anonymous>"
}
}
Has anyone an idea what is wrong? I would be really thankful for help.
Your problem is your model file, not the transaction code. You need Assembler not BU in the relationship field for Item and for Trade
Your asset should be:
asset Item identified by itemId{
o String itemId
o String name
o String idgId
o String serialNumber
o String comment
--> Assembler owner
--> Item [] items optional
}
as Assembler is the resource class (not BU, which is an extended class - there is no registry for this).
Your transaction Trade should also reflect the same resource ie (not BU) :
transaction Trade{
--> Item item
--> Assembler newOwner
}
Other than that, it should work fine with your existing code (have tested it against a Fabric network, using the following example Trade transaction in my REST API, where previous owner was Assembler#1 and it changes related Items from the items array for Item #1)
{
"$class": "org.dps.track.Trade",
"item":"resource:org.dps.track.Item#1",
"newOwner":"resource:org.dps.track.Assembler#2"
}
I modified model file and now whe n trying to generate rest API i only get System(General business network methods), no Item, BU and Trade API, why is this happening?
cto:
/**
* New model file
*/
namespace org.dps.track
//asset section
asset Item identified by itemId{
o String itemId
o String name
o String idgId
o String serialNumber
o String comment
--> BU owner
--> Item [] items optional
}
//participant section
participant BU identified by buId{
o String buId
o String name
o String country
o String city
o participantType type
}
//tranasaction section
transaction Trade{
-->Item item
-->BU newOwner
}
enum status {
o IN_TRANSIT
o DEPARTURED
o DELIVERED
}
enum participantType{
o Manufacturer
o Assembler
}
cc:
/**
* Sample transaction processor function.
* #param {org.dps.track.Trade } trade - the sample transaction instance.
* #transaction
*/
async function tradeCommodity(trade) {
const factory = getFactory();
trade.item.owner = trade.newOwner;
var list = [];
if (trade.item.items && trade.item.items.length > 0) {
trade.item.items.forEach((asset) => {
list.push(asset);
});
}
const assetRegistry = await getAssetRegistry('org.dps.track.Item');
// persist the state of the current ITEM
await assetRegistry.update(trade.item);
for (var i = 0; i < list.length; ++i) {
let res = await assetRegistry.get(list[i].getIdentifier());
res.owner = factory.newRelationship('org.dps.track', 'BU', trade.newOwner.getIdentifier());
// persist the state of the ITEM with new owner as a relationship
await assetRegistry.update(res);
}
}
I am trying a test a use case where I have taken two assets: a car and parts. I want to link the car with different instances of parts using a transaction. My model and js files are below :
namespace org.sample.test
asset Part identified by partId {
o String partId
o String partName
o String partManufacturer
}
asset Car identified by Vin {
o String Vin
--> Part part optional
o String modelNumber
}
transaction MakeCar{
o String carid
o String carmodel
o String[] PartId
}
/**
* Sample transaction processor function.
* #param {org.sample.test.MakeCar} tx The sample transaction instance.
* #transaction
*/
async function makecar(tx) { // eslint-disable-line no-unused-vars
var factory = getFactory();
var vehicle = factory.newResource('org.sample.test','Car',tx.carid);
vehicle.modelNumber = tx.carmodel;
var part = factory.newRelationship('org.sample.test','Part',tx.PartId);
vehicle.part = part;
const assetRegistry = await getAssetRegistry('org.sample.test.Car');
await assetRegistry.add(vehicle);
// Update the asset in the asset registry.
}
I also tried first creating the asset using the getfactory then creating relations by traversing partIds one by one using array but then as my Car asset is not created yet its throwing error.
I updated my transaction fucntion :
async function makecar(tx) { // eslint-disable-line no-unused-vars
var factory = getFactory();
var part;
var vehicle = factory.newResource('org.sample.test','Car',tx.carid);
vehicle.modelNumber = tx.carmodel;
var i=0;
while (i<tx.PartId.length)
{
part = factory.newRelationship('org.sample.test','Part',tx.PartId[i]);
vehicle.part = part;
i++;
}
assetRegistry = await getAssetRegistry('org.sample.test.Car');
await assetRegistry.add(vehicle);
}
Now its giving error : t: Instance org.sample.test.Car#OOOO has property part with type org.sample.test.Part that is not derived from org.sample.test.Part[]
the problem is this line:
var part = factory.newRelationship('org.sample.test','Part',tx.PartId);
it should be [something like]:
var part = factory.newRelationship('org.example.trading','Part',tx.PartId[0]); // 1st element of an array
its because you've defined tx.PartId as an array of relationships in your transaction definition, so you need to access the relevant element.
At this point, I'm not sure how you want to move forward, but your Car (vehicle) asset has an optional one to one relationship with Part (part Id) which is the optional field in your model. Perhaps it needs to be an array of relationships ? -> Part[] part optional But replacing the line above, will at least have it working, in its present form. An example of using an array of relationships is shown in the answer in this SO: -> Creating new participant and adding array of assets by reference to it (in particular :shares array in the model there)
i made a business network using hyperledger composer playground i want add an asset in the registry but while adding it is saying that t: Instance com.acn.hps.aops.ims.EvidenceDoc#4439 missing required field owner
.cto file
asset EvidenceDoc identified by evidenceId{
o String evidenceId
o Owner owner
}
participant Owner identified by AuthorityId{
o String AuthorityId
}
transaction addasset{
o EvidenceDoc evidenceDocJson
}
.qry file
.qry file
enter code here
query getOwnerbyId{
description: "Get owner of the evidence asset by its ID"
statement:
SELECT com.acn.hps.aops.ims.Superuser
WHERE (AuthorityId == _$AuthorityId)
}
logic.js file
/**
* #param {com.acn.hps.aops.ims.AddEvidence} addAsset
* #transaction
*/
function AddingEvidence(addAsset){
return getAssetRegistry('com.acn.hps.aops.ims.EvidenceDoc')
.then(function (AssetRegistry) {
// Get the factory for creating new asset instances.
var factory = getFactory();
var result = query('getOwnerbyId',
{AuthorityId:'1'/*addAsset.evidenceDocJson.owner.AuthorityId*/});
// Create the Evidence.
var evidence = factory.newResource('com.acn.hps.aops.ims', 'EvidenceDoc',
addAsset.evidenceDocJson.evidenceId);
evidence.owner = result[0]
// Add the asset to the asset registry.
return AssetRegistry.add(evidence);
})
}
I don't think the query is needed here. Try this.
.cto
namespace com.acn.hps.aops.ims
asset EvidenceDoc identified by evidenceId{
o String evidenceId
o Owner owner
}
participant Owner identified by AuthorityId{
o String AuthorityId
}
transaction addasset{
o EvidenceDoc evidenceDocJson
}
script.js
/**
* #param {com.acn.hps.aops.ims.addasset} addAsset
* #transaction
*/
function AddingEvidence(addAsset){
return getAssetRegistry('com.acn.hps.aops.ims.EvidenceDoc')
.then(function (AssetRegistry) {
// Get the factory for creating new asset instances.
var factory = getFactory();
// Create the Evidence.
var evidence = factory.newResource('com.acn.hps.aops.ims', 'EvidenceDoc',
addAsset.evidenceDocJson.evidenceId);
evidence.owner = addAsset.evidenceDocJson.owner
// Add the asset to the asset registry.
return AssetRegistry.add(evidence);
})
}
So your transaction name needs to match the param section ('addAsset' uppercase) in your transaction logic:
Also would suggest to pass owner as relationship to transaction
In your model
transaction addAsset {
o String evidenceId
--> Owner owner
}
In your transaction code (something like):
/**
* #param {com.acn.hps.aops.ims.addasset} addAsset
* #transaction
*/
function AddingEvidence(addAsset){
console.log('participant is ' + addAsset.owner.AuthorityID);
console.log('getCurrentparticipant is ' + getCurrentParticipant());
// Get the factory for creating new asset instances.
var factory = getFactory();
// Create the Evidence.
var evidence = factory.newResource('com.acn.hps.aops.ims', 'EvidenceDoc', addAsset.evidenceId);
evidence.owner.ID = addAsset.owner.AuthorityID;
return getAssetRegistry('com.acn.hps.aops.ims.EvidenceDoc')
.then(function (registry) {
return registry.add(evidence );
});
}
function Exchange(exchange){
// We do the actual exchange here:
// We first need to get both actual nodes:
var nodeIdFrom=exchange.nodeIdFrom;
var quantity =exchange.quantity;
var price = exchange.price;
var nodeIdTo =exchange.nodeIdTo;
return getParticipantRegistry('org.acme.mynetwork.Node')
.then(function(ParticipantRegistry){
ParticipantRegistry.get(nodeIdFrom)
.then(function(Participant){
Participant.Need=Participant.Need+quantity;
Participant.Balance_account=Participant.Balance_account+quantity*price;
return ParticipantRegistry.update(Participant);
});
});
I'm trying to execute a transaction defined as:
transaction Exchange{
o String nodeIdFrom
o String nodeIdTo
o Double quantity
o Double Price
}
To execute a transaction (we take money somewhere and put it somewhere else). With only the ids of the nodes as a parameter.
But right now that function does not work, you can execute it on the playground but my node is not modified.
Is it possible to apply a transaction without giving node as Node (node is a Participant).
it should work - here's an example (Using a fictitious sample 'Trader' Network and like you, I have defined 'qty' as a 'Double' in the Transaction model definition itself) of updating an Asset by a specific identifier (you're doing something similar - Participant by ID) and then - updating the asset's quantity using the Promises chain below. Suggest to use console.log() for outputs too when debugging.
So - given Transaction model:
transaction TraderById {
o String tradeId
o String tradingSymbol
o Double qty
}
and an Asset modeled as:
asset Commodity identified by tradingSymbol {
o String tradingSymbol
o String description
o String mainExchange
o Double quantity
--> Trader owner
}
you can update the Asset quantity ('quantity') as follows:
/**
*
* #param {org.acme.trading.TraderById} tradeById - the trade to be processed
* #transaction
*/
function TradeById(tradeById){
var commodityRegistry;
return getAssetRegistry('org.acme.trading.Commodity')
.then(function(registry){
commodityRegistry=registry;
return commodityRegistry.get(tradeById.tradingSymbol);
})
.then(function(result){
result.quantity-=tradeById.qty;
return commodityRegistry.update(result);
});
}