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
Related
Currently learning a bit about chaincode development using GO (recently worked with ethereum). I have the following code:
type Person struct {
name string // assume json fields for marshaling etc.
lastname string // ...
SSN string // ...
}
func (p *Person) Init(stub shim.ChaincodeStubInterface) Response {
args := stub.GetArgs()
var person Person
// just assume that args[0] is a json
json.Unmarshal(args[0], person )
p.name = person.name
p.lastname = person.lastname
p.SSN = person.SSN
}
......
During the init function I pass a person on the initialization of the chaincode. My question then is: upon another call against the chaincode. Will the p instance still be persisted from the init function such that I can read p.name given during the init? How does chaincode manage this?
You may find it appears to be persisted if you try it, but it will only be persisted in memory. If the chaincode restarts, or if the peer restarts, then the data will be lost. So this is not a recommended approach.
Chaincode has access to various stores - the world state (similar to the world state in Ethereum) and private data collections. Data stored in the world state is shared across all members of the channel.
You can put data into the world state using stub.PutState(key, value), and get data back from the world state using stub.GetState(key). Your Init function should store the data in the world state, and then your Invoke function can get the data out of the world state when any transactions are processed.
I recommend you check out the FabCar sample if you haven't already: https://github.com/hyperledger/fabric-samples/blob/release-1.4/chaincode/fabcar/go/fabcar.go
The initLedger transaction adds 10 cars to the world state. The queryCar transaction reads a car from the world state. There are other transactions for querying all of the cars, or updating a cars owner.
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.
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.
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"
}
One type of transaction in NetSuite is "Currency Revaluation" and there are examples of such transactions (e.g. see those with InternalIDs 3335, 3346 and 3347 in the NetSuite testdrive sample data, Honeycomb Mfg). I would like to know how to retrieve these transactions using the SuiteTalk web service API. I can get other types of transaction very easily, for example using the following Java code (simplified for clarity):
TransactionSearchBasic srch = new TransactionSearchBasic();
srch.setRecordType(new SearchStringField(RecordType._invoice, SearchStringFieldOperator.is));
SearchResult res = stub.search(srch);
if (res.getStatus().isIsSuccess()) {
for (Record rec : res.getRecordList().getRecord()) {
Invoice inv = (Invoice) rec;
// ... do things with inv ...
}
}
Now the problem is that, while there are many different transaction record types in SuiteTalk, such as the above (RecordType.invoice and class Invoice), there doesn't seem to be a record type for currency revaluations defined in the web service. How do you search for these?
If the transaction you need in this case fxreval is not in the section of schema browser, you can not access it from webservice.
https://system.na1.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2016_2/schema/record/fairvalueprice.html