hyperledger composer adding Participants to array of Participants in transaction process - hyperledger-fabric

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

Related

How can I manage my assets in hyperledger composer?

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.

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.

Hyperledger transaction Permission to participant based on some 3rd resource

I was working on some permission logic for Hyperledger , When need arise for a condition where i need to use 3 resources in permission.acl condition.
To Brief about scenario Let us suppose Resource Transaction is t for which Read Permission needs to be given, Participant is P Who needs to read transaction t.
Now Transaction t contains an identifier name for Asset A .
So I want to make a condition like if Asset A where Identifier(name) is equal to to the transaction T name , compares the Asset A registrar(This will hold participant name) with the Participant P Identifier. And If comparison is successful then give read permission of Resource(Transaction T) to Participant P.
Eg Snippet.
Asset ABC identified by name{
o String name;
--> Company registrar; (Company is type of participant)
}
Transaction CreateABC{
o String name;
}
So Participant P of type company should have permission to Read Transaction CreateABC if the Asset containing createABC.name has registar equal to P.getIdenitifer();
I have read that We can create separate functions in js file and call that from permission.acl but i am not yet able to fulfill this scenario.
An example of using 3 resources would be something like (example):
// first, access to invoke the transaction resource itself
rule Transaction_access {
description: "Can generate transaction"
participant: "org.acme.account.AccountTrader"
operation: CREATE
resource: "org.acme.account.TransferAmount"
action: ALLOW
}
// next, the (example) dynamic ACL rule that evaluates between who the transaction is being done
rule BiTrade_betweenTraders_only {
description: "Only Allow Updatee between Transferor/Transferee via named transaction"
participant(p): "org.acme.account.AccountTrader"
operation: ALL
resource(v): "org.acme.account.BankAccount"
transaction(tx): "org.acme.account.TransferAmount"
condition: ( p.getIdentifier() === v.owner.getIdentifier() && v.getIdentifier() === tx.targetAccount.getIdentifier() )
action: ALLOW
}
UPDATED with item 2:
An example of giving access to a transaction resource, based on an Asset ownership by a participant (both derived from the transaction object) might be:
rule my_restricted_Transaction_access {
description: "as per description above"
participant(p): "org.acme.account.AccountTrader"
operation: CREATE
resource(v): "org.acme.account.TransferAmount"
condition: ( p.getIdentifier() === v.account.owner.getIdentifier() )
action: ALLOW
}
where TransferAmount might be defined as:
transaction TransferAmount {
--> Account account // asset
}
and account has an --> owner field pointing back to AccountTrader ( the participant, in my original example - etc etc) - bear in mind, your ACLs would have to allow the participant to have access to the relevant asset and asset owner target resource too.
obviously this is a simple example - but you can define your function (to do the equivalent check, for your model) in the condition section. If you've added the JS script to your BNA under /lib (and upgraded the business network on Fabric to take effect) - you then just have to worry about whether your function name is what you called it (again, the links I sent you should provide a clear example of it in use).
Calling a function as part of your ACL condition is straightforward - you can see an example of this in this github test file -> the function (JS) is here https://github.com/hyperledger/composer/blob/master/packages/composer-tests-functional/systest/data/accesscontrols.js#L23 and the corresponding (calling) ACL ruleset is here -> https://github.com/hyperledger/composer/blob/master/packages/composer-tests-functional/systest/data/accesscontrols.acl#L124
UPDATED item 3:
eg in your permissions.acl file a rule like:
rule rule_func_condition {
description: "Allow all participants access to all resources"
participant(p): "org.acme.account.AccountTrader"
operation: CREATE
resource(a): "org.example.account.TransferAmount"
condition: (testOwnership(a, p))
action: ALLOW
}
in your functions.js (or whatever) in the /lib folder (or you can have it your existing logic.js if you prefer, however you want to do it):
/**
* Test that the specified asset is owned by the specified participant.
* #param {Resource} asset The asset.
* #param {Resource} participant The participant.
* #return {boolean} True if yes, false if no.
*/
function testOwnership(asset, participant) {
return asset.owner.getIdentifier() === participant.getIdentifier();
}
where asset and participant objects are passed into this particular function example.

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

Includes function in ACL condition

I have an asset called MedicalFile which contains a reference to an organization. The participant HealthCareProfessional also belongs to an organization.
Now I'd like to define an ACL rule which limits the health care professional to only view medical files which MedicalFile's are connected to his organisation.
I came up with the following rule:
rule OrganisationMedicalFilePermission {
description: "An organisation may updates a medical file which they have permission from"
participant(h): "nl.epd.blockchain.HealthCareProfessional"
operation: ALL
resource(m): "nl.epd.blockchain.MedicalFile"
condition: (m.organisations.includes(h.organisation))
action: ALLOW
}
This results in an empty array once I invoke the RESTful API with Loopback. I'm authenticated as a health care professional.
Assets & Participant:
asset Organisation identified by id {
o String id
o String name
o String city
o String zipCode
o String street
o String houseNumber
o String houseNumberExtra optional
o OrganisationType organisationType
}
asset MedicalFile identified by bsn {
o String bsn
--> Patient owner
--> Patient[] mentors optional
--> Organisation[] organisations optional
o Visit[] visits optional
o String[] allergies optional
o Treatment[] treatments optional
o Medicine[] medicine optional
}
participant HealthCareProfessional identified by bsn {
o String bsn
o String firstName
o String namePrefix optional
o String lastName
--> Organisation organisation
}
My question is if it's possible to create a condition which validates this problem. If not, what are my options?
It's a good question; there's an updated ACL below that I've tested using the online playground.
This is the updated rule:
rule LimitAccess {
description: "An organisation may updates a medical file which they have permission from"
participant(h): "nl.epd.blockchain.HealthCareProfessional"
operation: ALL
resource(m): "nl.epd.blockchain.MedicalFile"
condition: (
m.organisations.some(function (organisation) {
return organisation.getIdentifier() === h.organisation.getIdentifier();
} )
)
action: ALLOW
}
The some function is the critical piece here to scan the array of relationships. Also note the use of the getIdentifier() function as well rather than trying to access the identifier directly.

Resources