Why do we need to create item and object on fabric chain? - hyperledger-fabric

I am looking at the sample codes of the hyperledger fabric NFT example and I see that after adding itemonchain in the ledger state, they add nftonchain in the ledger state as well.
Why do we need to add 2 different objects in the chain?
I refer to these lines from the code
let item = objectBuilder.itemOnchainStruct(payload, imageName, imageHash, signedDataStr);
let nft = objectBuilder.nftOnchainStruct(item, payload, callerInfo.username, aesKey);
let payloadForOnchain = [];
payloadForOnchain.push(JSON.stringify(item));
payloadForOnchain.push(JSON.stringify(nft));

Related

Updating same list, multiple times in the same method - Hyperledger Fabric Chaincode node js

So I was trying to build a simple loyalty chaincode in js.
I started with this repo: https://github.com/IBM/customer-loyalty-program-hyperledger-fabric-VSCode/blob/master/contract/lib/customerloyalty.js
And I was trying to write a function where two users could change points between them. Which means that I had to update the member1 on the member's list and member2 on the member's list.
The problem is that I am not able to update both members. Only the last one (member2) is registered on the member's list with the update points value.
This is the function for adding the elements to the list and put it on the blockchain state:
async function addElementToList(ctx, listKey, elementJSON){
let currentList = await ctx.stub.getState(listKey);
currentList = JSON.parse(currentList);
currentList.push(elementJSON);
await ctx.stub.putState(listKey, Buffer.from(JSON.stringify(currentList)));
}
And this I what I'm trying to do in my Exchange Points function:
//update member's points
member2.points += exchangePoints.points;
member1.points -= exchangePoints.points;
let member1_Stringify = JSON.stringify(member1);
let member2_Stringify = JSON.stringify(member2);
let exchangePointsStringify = JSON.stringify(exchangePoints);
await utils.addElementToList(ctx, allMembersKey, member1_Stringify); //update member1 in member's list
await utils.addElementToList(ctx, exchangePointsKey, exchangePointsStringify); //add to earn points list
await utils.addElementToList(ctx, allMembersKey, member2_Stringify); //update member2 in member's list
return exchangePointsStringify;
Anyone knows how can I fix this?
Thanks a lot!
The problem is that you can't read your own writes in chaincode, as described in the Read-Write set semantics documentation. Basically if you have a key that currently contains the text current stuff in the world state (ie has been committed) and you do the following
await ctx.stub.putState(key, Buffer.from('new data'));
const readvalue = ctx.stub.getState(key).toString();
then readvalue will contain the original value of current stuff (ie the current value on the ledger) it won't contain the value you have just written.

behavior of chaincode during runtime

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.

Can't confirm any actors are being created

In Service Fabric I am trying to call an ActorService and get a list of all actors. I'm not getting any errors, but no actors are returned. It's always zero.
This is how I add actors :
ActorProxy.Create<IUserActor>(
new ActorId(uniqueName),
"fabric:/ECommerce/UserActorService");
And this is how I try to get a list of all actors:
var proxy = ActorServiceProxy.Create(new Uri("fabric:/ECommerce/UserActorService"), 0);
ContinuationToken continuationToken = null;
CancellationToken cancellationToken = new CancellationTokenSource().Token;
List<ActorInformation> activeActors = new List<ActorInformation>();
do
{
var proxy = GetUserActorServiceProxy();
PagedResult<ActorInformation> page = await proxy.GetActorsAsync(continuationToken, cancellationToken);
activeActors.AddRange(page.Items.Where(x => x.IsActive));
continuationToken = page.ContinuationToken;
}
while (continuationToken != null);
But no matter how many users I've added, the page object will always have zero items. What am I missing?
The second argument int in ActorServiceProxy.Create(Uri, int, string) is the partition key (you can find out more about actor partitioning here).
The issue here is that your code checks only one partition (partitionKey = 0).
So the solutions is quite simple - you have to iterate over all partitions of you service. Here is an answer with code sample to get partitions and iterate over them.
UPDATE 2019.07.01
I didn't spot this from the first time but the reason why you aren't getting any actors returned is because you aren't creating any actors - you are creating proxies!
The reason for such confusion is that Service Fabric actors are virtual i.e. from the user point of view actor always exists but in real life Service Fabric manages actor object lifetime automatically persisting and restoring it's state as needed.
Here is a quote from the documentation:
An actor is automatically activated (causing an actor object to be constructed) the first time a message is sent to its actor ID. After some period of time, the actor object is garbage collected. In the future, using the actor ID again, causes a new actor object to be constructed. An actor's state outlives the object's lifetime when stored in the state manager.
In you example you've never send any messages to actors!
Here is a code example I wrote in Program.cs of newly created Actor project:
// Please don't forget to replace "fabric:/Application16/Actor1ActorService" with your actor service name.
ActorRuntime.RegisterActorAsync<Actor1> (
(context, actorType) =>
new ActorService(context, actorType)).GetAwaiter().GetResult();
var actor = ActorProxy.Create<IActor1>(
ActorId.CreateRandom(),
new Uri("fabric:/Application16/Actor1ActorService"));
_ = actor.GetCountAsync(default).GetAwaiter().GetResult();
ContinuationToken continuationToken = null;
var activeActors = new List<ActorInformation>();
var serviceName = new Uri("fabric:/Application16/Actor1ActorService");
using (var client = new FabricClient())
{
var partitions = client.QueryManager.GetPartitionListAsync(serviceName).GetAwaiter().GetResult();;
foreach (var partition in partitions)
{
var pi = (Int64RangePartitionInformation) partition.PartitionInformation;
var proxy = ActorServiceProxy.Create(new Uri("fabric:/Application16/Actor1ActorService"), pi.LowKey);
var page = proxy.GetActorsAsync(continuationToken, default).GetAwaiter().GetResult();
activeActors.AddRange(page.Items);
continuationToken = page.ContinuationToken;
}
}
Thread.Sleep(Timeout.Infinite);
Pay special attention to the line:
_ = actor.GetCountAsync(default).GetAwaiter().GetResult();
Here is where the first message to actor is sent.
Hope this helps.

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.

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

Resources