How can I manage my assets in hyperledger composer? - hyperledger-fabric

In my hyperledger composer project I have a medicine as an asset. There are different types of medicine, but all medicine need to be approved before they are allowed to be produced and distributed in the supply chain.
Can I store a list of allowed assets in the blockchain, a list which can grow or shrink? Or do I have to store it off-chain?
edit: grammar mistake fixed.

Based on your reply to Riccardo Bonesi, I suggest something like this
asset AllowedMedicines identified by id {
o String id
o Medicines[] medicines
}
concept Medicines {
o String medicineId
o String medicineName
o Participants[] allowedParticipants
}
concept Participants {
o String participantId // either this is one below
--> Participant somePerson
// Any specific meta data you want to store
}
Now in your .js files you can do something like this
const allowedMedicines = await registry.get(id);
const participant; // The person you are checking for
const medicineId; // The medicine against which you are checking
const medicines = allowedMedicines.medicines;
if (medicines.medicineId.contains(medicineId)) {
// Medicine is in the list;
let allowedParticipants = medicines.allowedParticipants;
if (allowedParticipants.contains(participant) {
// The participant is allowed access to the medicine
};
};
Now of course based on the composer version, some syntax may need to be tweaked, but is the general idea of how you can maintain a mapping.

Related

Can i make changes to the parameters defined in relationships

1.i want to know whether i can make changes to the parmeter defined in the relationship.
what i want to do is to make a function with name of bookflight and then make changes to the number of seats if the flight is booked .
these are my cto files
namespace org.acme.airline.aircraft
/** Aircraft is an ACME Asset*/
asset Aircraft identified by aircraftId {
o String aircraftId
o Ownership ownershipType default="LEASED"
// Number of seats per class
o Integer firstClassSeats range = [4,]
o Integer businessClassSeats range = [6, 20]
o Integer economyClassSeats range = [30, ]
o String nickName optional
}
enum Ownership {
o LEASED
o OWNED
}
and for flight the code is
namespace org.acme.airline.flight
import org.acme.airline.aircraft.Aircraft
asset Flight identified by flightId {
// Solution to the exercise - try out the Regular expression at http://regex101.com
// Share your optimized regular expression with others :)
o String flightId regex=/[A-Z][A-Z][0-9][0-9][0-9]-[0-9][0-9]-[0-3][0-9]-[0-9][0-9]/
o String flightNumber
o Route route
o String[] aliasFlightNumber optional
--> Aircraft aircraft optional
}
concept Route {
o String origin regex=/[A-Z][A-Z][A-Z]/
o String destination regex=/[A-Z][A-Z][A-Z]/
o DateTime schedule
}
// Logistics department of ACME creates the flights
transaction CreateFlight {
o String flightNumber
o String origin
o String destination
o DateTime schedule
}
event FlightCreated {
o String flightId
}
// Assigns an aircraft to the flight
// The logistics / validation on availability of aircraft
// Kept outside of the Blockchain
transaction AssignAircraft {
o String flightId
o String aircraftId
}
// Event indicating that aircraft was assigned
event AircraftAssigned {
o String flightId
o String aircraftId
}
now what i want to make changes to reltionship in the flight
to make changes to it what should i do . i have made a javascript file.to
access make changes in it.
function booktickets(registry){
//array to recored the hold the instances of aircraft resourse
const bnDef = bnUtil.connection.getBusinessNetwork();
const factory = bnDef.getFactory();
let flightResource = factory.newResource(aircraftNamespace,aircraftType,'AE201-05-05-2020');
flightResource.setPropertyValue('flightNumber','AE101');
flightResource.route = factory.newConcept(aircraftNamespace,'Route');
flightResource.route.setPropertyValue('origin', 'DEL');
flightResource.route.setPropertyValue('destination' , 'APH');
flightResource.route.setPropertyValue('schedule' , new Date('2018-10-15T21:44Z'));
flightResource.aircraft = factory.newRelationship('org.acme.airline.aircraft', 'Aircraft', 'CRAFT01');
//.setPropertyValue()
flightResource.aircraft.setPropertyValue('ownershipType','LEASED');
flightResource.aircraft.setPropertyValue('firstClassSeats',10);
flightResource.aircraft.setPropertyValue('businessClassSeats',10);
flightResource.aircraft.setPropertyValue('economyClassSeats',100);
return registry.update(flightResource).then(()=>{
console.log('Successfully created the flight!!!');
bnUtil.disconnect();
}).catch((error)=>{
console.log(error);
bnUtil.disconnect();
});
}
your question appears to be: can you create a relationship from Flight (asset) to Aircraft (asset) in a transaction function (that operates in the chaincode runtime), and can you update the fields of the related Aircraft (in its separate registry). The answer is 'yes', you can, for both. You don't provide the model for the bookflight function, so can only make assumptions about its model definition. as a minimum (based on your code) it will need:
transaction bookflight { }
A code example of what you are trying to do with relationships - is shown here -> https://github.com/hyperledger/composer-sample-networks/blob/master/packages/perishable-network/lib/logic.js#L130
This section:
const bnDef = bnUtil.connection.getBusinessNetwork();
const factory = bnDef.getFactory();
is composer-client code - and will not work inside a transaction function (that is runtime code, you need to remove client code - the example below shows 'how' to do it.) Replace line 2 with :
const factory = getFactory();
See more on transaction functions, examples etc at https://hyperledger.github.io/composer/latest/reference/js_scripts
note: you can just assign values like:
flightResource.route.origin = 'DEL' ; // no need for.setPropertyValue('origin', 'DEL'); etc etc
I don't see your code to update the Aircraft registry (with flightResource.aircraft FYI) - but you would need that to update the fields in that related asset (presently, you're only updating the Flight registry above )
new Date() is non deterministic code - if you're hoping to achieve consensus from multiple peers/orgs.
You'll notice the link I sent earlier, shows the use of async/await rather than JS promises (.then etc etc) - easier to code, easier to read. cheers.

display data from 2 assets using single query in hyperledger faric ?

i have these two assets :
1]
asset bloodBankInformations identified by bloodBankId {
o String bloodBankId
o contact bloodBankContactDetails
--> bloodData bloodBankBloodData
}
2]
asset bloodData extends bloodBankInformations {
o String bloodDatakey
o bloodquotas bloodquota
}
now i want to query on this asset such that i can get data from both assets in one single query.
Composer Queries are run against a single Asset or Participant registry. There is no 'join' as you might see in a relational database.
However for your example it is possible to use a Filter on the REST server to filter the results (like a Query) and resolve the relationship of relationship fields.
Before showing you my example I wonder if you really wanted to 'extend' original asset? So I have simplified your model in my example - but the same principle works if you did intend to extend.
Model:
asset bloodBankInformations identified by bloodBankId {
o String bloodBankId
o contact bloodBankContactDetails
--> bloodData bloodBankBloodData
}
asset bloodData extends bloodBankInformations {
o String bloodDatakey
o bloodquotas bloodquota
}
Filter:
On the REST server used on GET on the endpoint /blookBankInformations
{"where":{"bloodBankId":"BB03"},"include":"resolve"}
My Response Body:
[
{
"$class": "org.acme.mynetwork.bloodBankInformations",
"bloodBankId": "BB03",
"bloodBankContactDetails": "Diferent address!",
"bloodBankBloodData": {
"$class": "org.acme.mynetwork.bloodData",
"bloodDatakey": "BL04",
"bloodquota": "Quota BBBB"
}
}
]
There is some additional information in the Composer Knowledge Wiki on filters.

hyperledger composer adding Participants to array of Participants in transaction process

I have defined Participant and asset as below and I want to add a particular participant to array of access[type Participant] in transaction. Can someone tell me how this can be done.
How can I add the participant identity to the array. How do I need to pass the identity through params and then add it to the array of participants. I have created the permissions according to the question I asked earlier. Link to the question for permission
ASSET DECLARATION
asset Details identified by detailsId {
o String detailsId
o String description optional
--> Bank owner
o Bank[] access optional
o String document
}
PARTCIPANT DECLARATION
participant Bank identified by bankId {
o String bankId
o String Name
}
You have made a small change to the model between the ACL example and this example - changing the access array which was a relationship before.
--> Bank[] access optional original
vs
o Bank[] access optional here
Based on the original model, first add this Transaction to the model:
transaction AddAccess {
--> Details details
--> Bank additionalAccess
}
Then, this scripted Transaction should work for you:
/**
* Adding a Bank to an access list
* #param {org.example.test.AddAccess} addA
* #transaction
*/
async function addAccess(addA) {
// Add the new access to the array, checking if empty first as it is optional field at creation
if (typeof addA.details.access == 'undefined') {
addA.details.access = new Array();
addA.details.access[0] = addA.additionalAccess;
}
else {
addA.details.access.push(addA.additionalAccess);
}
// get the Registry
const assetRegistry = await getAssetRegistry('org.example.test.Details');
// Update the Registry with the new details
await assetRegistry.update(addA.details);
}
Test with JSON like this:
{
"$class": "org.example.test.AddAccess",
"details": "resource:org.example.test.Details#D11",
"additionalAccess": "resource:org.example.test.Bank#9241"
}

How logic.js file work in Hyperledger Composer?

In Hyperledger Composer, is logic.js related to Transaction?
How to access list from logic.js?
Have any good tutorial to understand what can I do in logic.js file?
Though, here is an answer, I'm explaining how logic.js related to a transaction, so that reader can understand.
Transaction is an asset transfer onto or off the ledger. In Hyperledger Composer transaction is defined in model (Contain .cto extension) file. In logic.js( can be anything.js) file contain the Transaction processor function to execute the transactions defined in the model file.
Here is sample model file:
/**
* My commodity trading network
*/
namespace org.acme.mynetwork
asset Commodity identified by tradingSymbol {
o String tradingSymbol
--> Trader owner
}
participant Trader identified by tradeId {
o String tradeId
o String firstName
o String lastName
}
transaction Trade {
--> Commodity commodity
--> Trader newOwner
}
In the model file, a Trade transaction was defined, specifying a relationship to an asset, and a participant. The Trade transaction is intended to simply accept the identifier of the Commodity asset which is being traded, and the identifier of the Trader participant to set as the new owner.
Here is a logic file which contain JavaScript logic to execute the transactions defined in the model file.
/**
* Track the trade of a commodity from one trader to another
* #param {org.acme.mynetwork.Trade} trade - the trade to be processed
* #transaction
*/
async function tradeCommodity(trade) {
trade.commodity.owner = trade.newOwner;
let assetRegistry = await getAssetRegistry('org.acme.mynetwork.Commodity');
await assetRegistry.update(trade.commodity);
}
Tutorial
Composer Official Documentation
IBM Blochain Developer Tutorial
Yes, but doesn't have to have the filename 'logic.js' exclusively. See more here https://hyperledger.github.io/composer/latest/reference/js_scripts
You model your Array fields first https://hyperledger.github.io/composer/latest/reference/cto_language.html then code it. Arrays are handled like any javascript array handling. See examples here -> https://github.com/hyperledger/composer-sample-networks/blob/master/packages/trade-network/lib/logic.js#L45 of results from a query being handled in an array. Also temperatureReadings is an array being handled in the sample networks here https://github.com/hyperledger/composer-sample-networks/blob/v0.16.x/packages/perishable-network/lib/logic.js#L37
I would encourage you to try out the tutorials to validate your understanding. https://hyperledger.github.io/composer/latest/tutorials/tutorials

How to implement unique key constraints in CouchDB

I use CouchDB and I would like all my users to have unique emails. I would expect that the database return a status 400 (bad request) when I try to duplicate an email.
But since there is no way to define constraints in CouchDB, I should implement it myself, my question is:
In which layer of my application should this rule stand?
(1) Domain objects layer
I don't really know how to implement it in this layer
(2) Interactor layer
This constraint could be implemented in interactors here since there is the place where business rules stand. But if there is multiple rules for single document it could add unnecessary complexity...
function createUser(userData) {
let email = userData.email;
let exist = await userDB.userExist(email);
if(exist) {
// return status 400
} else {
// create user
}
}
(3) Database gateway layer
The constraint can also be implemented in the database gateway layer. Usually we'll have a gateway for each specific entity. But does that means that external services adapters contains a bit of business logic?
class userDB() {
constructor(opts) {
this.db = opts.db.connect();
}
async userExist(email) {
return await this.db.fetchByView('email', email);
}
async create(email) {
let exist = await this.userExist(data.email);
if(exist) {
// throw error
} else {
// create the user
}
}
}
Unique email address is a very old DDD topic. It relates to the set validation.
The simplest (and from my point of view is also the best) is to place a constraint at the database level.
From what I know, the only whay to create an unique constraint in CouchDB is to use the _id field so you can use this solution. This idea is to put the email in the _id field.
let exist = await this.userExist(data.email);
if(exist) { // throw
error } else { // create the user }
This method is not safe for concurrent updates. Two users can be created at the same time. Imagine that for both the requests the this.userExist(data.email) is returning false.
I am not a CouchDB expert but from pure Clean Architecture perspective ensuring unique email addresses is a business rule which should be implemented in an interactor.
With this approach ur business rule would remain intact even if u would once decide to replace the detail CouchDB with some other detail - another storage system.

Resources