How can I get an endorsement back from a specific peer? - hyperledger-fabric

Is there a way to get endorsements back from specific peer(s) after submitting a transaction in Hyperledger fabric, using contract.submitTransaction() or channel.sendTransaction()?
So far the endorsements always seem to come back from the same peer and not other peers in the organization. Please see my environment details below.
Also if I target specific peers using the node sdk sendTransactionProposal(request)'s ChaincodeInvokeRequest preferred or ignore list, that doesn't seem to make any difference.
Is there any specific documentation or an alternative resource available that addresses this issue?
ChaincodeInvokeRequest{
targets: allPeers or peer2, // or a different peer
preferred: peer2,
ignore, peer1
}
Environment details
Current setup:
1 org with 2 peers
Simple Endorsement policy:
{"identities":[{"role":{"name":"member","mspId":"Org1MSP"}}],policy:{"1-of":[{"signed-by":0}]}}
Fabric sdk libraries:
fabric-ca-client - v1.4.1
fabric-client - v1.4.1
fabric-network - v1.4.1
Hyperledger Fabric version: v1.4.1
Using the following approach to target specific peers in the sdk:
const request = {
targets: peers or peer[1] or [peer2], -- target specific peer
chaincodeId: chaincodeName,
txId,
fcn: functionName,
args,
transientMap: transientMapData // , // private data,
ignore: list of peer[s] to ignore
preferred: list of peer[s] to prefer
};
const endorsementResults = await channel.sendTransactionProposal(request);
if (channel.verifyProposalResponse(endorsementResults[0][0])) {
const transactionRequest = {
proposalResponses: endorsementResults[0],
proposal: endorsementResults[1]
};
invokeResponse = await channel.sendTransaction(transactionRequest);
}
Expected results:
transaction1 - client submits a transaction to peer1 and gets an endorsement back from peer1.
transaction2 - client submits a transaction to peer2 and gets an endorsement back from peer2.
Actual results:
transaction1 - client submits a transaction to peer1 and gets an endorsement back from peer1.
transaction2 - client submits a transaction to peer2 and gets an endorsement back from peer1.

Related

How could I capture events generated by transactions on Hyperledger Fabric?

I'd like to know if chaincode events can be captured by all peers of a specific channel that have installed the chaincode through SDK. I tried some experiments but it seems that a chaincode event can be captured only by the peer that required the specific transaction but I need all peers of a channel receive that specific event.
The events which the chaincode emits are stored in the transaction.
In your case, you will need to connect to a peer and listen for contract events.
This is an example of Node.JS client:
const n = await gateway.getNetwork("mychannel");
const contract: network.Contract = n.getContract("fabcar");
contract.addContractListener(async (event) => {
console.log(event.eventName, event.payload.toString("utf-8"));
});
The output will be:
itemCreated 1f6629d7-999b-4cbb-8b36-68e1de2aa373
Then in the chaincode, you will set an event, this is an example in Java:
ctx.getStub().setEvent("itemCreated", StringUtils.getBytes(item.id, StandardCharsets.UTF_8));
If you want to investigate which events are in a transaction, you can fetch the block by executing the following scripts:
BLOCK_NUMBER=1 # whatever block you want to fetch
peer channel fetch -c mychannel ${BLOCK_NUMBER}
configtxlator proto_decode --input mychannel_${BLOCK_NUMBER}.block --type common.Block > mychannel_${BLOCK_NUMBER}.json
And then you will see in the JSON a key called events:

How to query a chaincode from outside an organization

I have 4 Orgs:
Org1 -- 2 peer
Org2 -- 2 peer
OrgCam -- 0 peer, 1 client
OrgView -- 0 peer, 1 client
Org1's peers have a chaincode installed on them that access some private data only available to Org1.
As a client of OrgCam, I want to access the chaincode installed on Org1's peers.
When I try to do that:
const result = await contract.evaluateTransaction('getPoints','ID1');
This error occurs
2019-05-19T15:20:20.084Z - error: [SingleQueryHandler]: evaluate: message=No peers available to query. Errors: [], stack=FabricError: No peers available to query. Errors: []
at SingleQueryHandler.evaluate (/home/zanna/fabric-samples/first-network/clientCode/node_modules/fabric-network/lib/impl/query/singlequeryhandler.js:39:17)
at Transaction.evaluate (/home/zanna/fabric-samples/first-network/clientCode/node_modules/fabric-network/lib/transaction.js:246:29)
at Contract.evaluateTransaction (/home/zanna/fabric-samples/first-network/clientCode/node_modules/fabric-network/lib/contract.js:172:39)
at main (/home/zanna/fabric-samples/first-network/clientCode/camera.js:41:39)
at <anonymous>, name=FabricError
Failed to evaluate transaction: FabricError: No peers available to query. Errors: []
My question is: How can I query the Org1's chaincode even if I'm not a client from Org1?
I am a bit confused by your configuration, but I'll try to answer as best as I can.
Lets make it clear
A chaincode does not "belong" to an organization. A chaincode belongs to a channel and has particular endorsement policies.
Considering that, you could say a chaincode belongs to the peers that are member of the channel.
An organization can only interact with a chaincode if it possesses a peer that is member of the channel that has the chaincode.
Answer
You did not provide any information about your channel. Considering you error, I suppose you did not join the OrgCam peer to the channel in which Org1 peer(s) deployed the chaincode.
You OrgCam peer is not part of the channel, you cannot query the chaincode of the channel.
Moreover, you cannot use a OrgCam client certificate to interact with a Org1 peer, because the certificate is not known/accepted by the Org1 peers. Only Org1 explicitly defined clients can interact with org1 peers.
I finally managed to do that.
1.
const result = await contract.evaluateTransaction('getPoints','ID1');
must be changed to:
const result = await contract.submitTransaction('getPoints','ID1');
in order to get the information from peers in an external organization.
2.
If private data are in use, it's important that the fields "memberOnlyRead" and "memberOnlyWrite" (1) must be removed or set to false in the collections_config.json file.
example:
[
{
"name": "collectionFacepoints",
"policy": "OR('Org1MSP.member')",
"requiredPeerCount": 2,
"maxPeerCount": 2,
"blockToLive": 0,
"memberOnlyRead": false
}
]
3.
In the gateway.connect(connectionProfile, connectionOptions) it is important to add discovery.enable=true to the connectionOptions.
example:
await gateway.connect(
connectionProfile,
{
wallet,
identity: identityConfig.identityLabel,
discovery: {
enabled: true,
asLocalhost: true
},
eventHandlerOptions: {
strategy: DefaultEventHandlerStrategies.NETWORK_SCOPE_ALLFORTX
}
}
);
4.
Unfortunately it seems that a client from OrgCam cannot directly query a chaincode installed in org1's peers, but It can be done adding an empty (2) OrgCam's peer that act as an anchor peer.
(1): "memberOnlyWrite" is not available yet. See here.
(2): With "empty" I mean without any chaincode installed on it.

Hyperledger fabric 1.2 service discovery error

I use Hyperledger Fabric 1.2 to build a blockchain cluster, which contains 3 peers and 3 orderers. I can successfully deploy and invoke the chaincode via both CLI and Java SDK. Everything works fine. However, when I notice the service discovery function and try to use it, I met two problems. First, after I build the discover tool and try to use it to get some discovered information, I can't access the peer and get the message as follow
"failed connecting to discovery service: failed to create new
connection: context deadline exceeded"
The config command is
discover --configFile conf.yaml --userKey ./crypto-config/peerOrganizations/org1.forchain.com/peers/peer0.org1.forchain.com/msp/keystore/7458b29b1fb6a89768585430dbf0e522a40ff4aefe600fc1e4fafe62c3c972e4_sk --userCert ./crypto-config/peerOrganizations/org1.forchain.com/peers/peer0.org1.forchain.com/msp/signcerts/peer0.org1.forchain.com-cert.pem --MSP Org1MSP saveConfig
The query command is
discover --configFile conf.yaml peers --channel lajiao --server localhost:6051
I guess it may be caused by the TLS config so I canceled the TLS and tried again. This time I successfully access the peer and get some messages, but I met another problem. When I use 'discover peers xxx ' command, I always get null result, in fact there are two peers in that channel. When I use 'discover endorsers xxx' command, I always get the following error message
'failed constructing descriptor for chaincodes:'
In the meantime, the peer log outputs the following message:
'Principal set computation failed: chaincode isn't installed on
sufficient organizations required by the endorsement policy 2018-08-01
10:21:50.860 UTC [discovery] chaincodeQuery -> ERRO 1441 Failed
constructing descriptor for chaincode chaincodes:
,: chaincode isn't installed on sufficient organizations required by
the endorsement policy'
I can assure that the chaincode is successfully installed in all peers. And I didn't use the endorsement policy when I instantiated the chaincode. I think it is not the policy problem because I still can invoke the chaincode and propose a transaction.
I also tried to use the Java SDK and found that I can get the orderer nodes info but I can't get the other peer nodes or chaincode info. The log always output: "Discover of chaincode names was empty.". But the chaincode is definitely instantiated and can be invoke via SDK. I refered to the test code in "org.hyperledger.fabric.sdkintegration.ServiceDiscoveryIT" and some key Java code is as follow:
channel.addPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY,Peer.PeerRole.LEDGER_QUERY, Peer.PeerRole.EVENT_SOURCE,Peer.PeerRole.CHAINCODE_QUERY)));
channel.initialize();
System.out.println("================ orderer ===============");
for (Orderer orderer : channel.getOrderers()) {
System.out.println(orderer.getName());
}
System.out.println("================ peer ===============");
for (Peer p: channel.getPeers()) {
System.out.println(p.getName());
}
System.out.println("================ chaincode ===============");
for (String s: channel.getDiscoveredChaincodeNames()) {
System.out.println(s);
}
So, how can I use the 'discover' command under TLS configuration and how can I get the discovered information?
For the config command - you need to pass a TLS root CA, via --peerTLSCA. Please look at the examples in the documentation and act accordingly.
Now - for the second problem, I think that the peers might not know each other in the channel.
Make sure you have anchor peers defined in the channel and that both peers have external endpoints configured.
Feel free to bug me (yacovm) on chat.hyperledger.org if you're struggling for too long and can't solve the problem.
You must add an anchor peer from each organization in the channel, this solved the problem for me. Anchor peers are required for the service discovery since the service discovery uses gossip protocol- thanks #yacovm
I stumbled a similar error (regarding to service discovery) as below.
Go Fabric Client logs:
Failed to get endorsing peers: error getting channel response for channel [myc]:
Discovery status Code: (11) UNKNOWN. Description: error received from Discovery Server:
failed constructing descriptor for chaincodes:<name:"mycc">
Peer logs:
Failed constructing descriptor for chaincode chaincodes:<name:"mycc" > ,:
cannot satisfy any principal combination
It's fixed when I provide CORE_PEER_GOSSIP_EXTERNALENDPOINT environment attribute with a correct value on peer's configuration (in docker yaml file in my case).
As I understood since this attribute is missing, discovery services running on peers failed to communicate with each other to have a conclusion of what current network looks like.

Hyperledger Fabric nodejs sdk performance issue

I am facing a performance issue while using Hyperledger fabric node.js sdk.
When I issue the invocation request to sdk and consume the response given by the chaincode by using the following code
var proposalResponse = results[0];
var proposal = results[1];
let isProposalGood = false;
if(proposalResponse
&& proposalResponse[0].response
&& proposalResponse[0].response.status === 200){
isProposalGood = true;
var res = JSON.parse(proposalResponse[0].response.payload.toString());
res.event_status = 'VALID'
resolve(res);
}else{
reject(createErrorResponse(proposalResponse[0].message,500))
return
}
The api responds within 50ms as you can see the screenshot below:
But, when I wait for orderer to confirm the transaction by using the following code:
if (code === 'VALID'){
//get payload from proposal response
var res = JSON.parse(proposalResponse[0].response.payload.toString());
res.event_status = 'VALID'
resolve(res);
}else{
var return_status = createErrorResponse("Transaction was not valid", 500);
return_status.tx_id = transaction_id_string
reject(return_status)
return
}
It takes nearby 2500ms to response as you can see the screenshot of postman below:
Correct me if I am wrong
I know it takes time because the orderer confirms the transaction and commits into the ledger. But don't you think we should proceed only if the orderer agrees to transaction and commits into the ledger. If yes, then it will take 2.5 seconds to response (network is running on docker in local machine & sdk on same machine) which is a performance issue.
What happen if data is written into the chaincode and after that orderers deny to write the transaction into the ledger?
Any help would be appreciated
the orderer confirms the transaction and commits into the ledger.
The task for the Ordering service (As the name suggests) is only to order the received endorsed transactions chronologically by channel and then deliver them to all the peers in the channel. Orderers don't actually commit the transactions into the ledger.
The Committer Peers do. And committing is a time-taking process since all the peers validate all the transactions within the block to ensure endorsement policy is fulfilled and to ensure that there have been no changes to ledger state for read set variables since the read set was generated by the transaction execution. Transactions in the block are tagged as being valid or invalid. Then Each peer appends the block to the channel’s chain, and for each valid transaction the write sets are committed to current state database. An event is emitted, to notify the client application that the transaction (invocation) has been immutably appended to the chain, as well as notification of whether the transaction was validated or invalidated.
So after knowing all these details in the Transaction Flow, It should be noted that the client application shouldn't wait for the response received by the orderer. Instead it should just request the orderer to deliver the endorsed transactions and the application should be subscribed to the events emitted by the peers so that it should know or be notified that the transactions are actually immutably committed in the channel's chain.
You can have further help regarding event subscription in the Fabric Node SDK docs.
What happen if data is written into the chaincode and after that
orderers deny to write the transaction into the ledger?
This is simply impossible as data is appended to the chain only when the transaction is validated through proper endorsements from the endorser peers (specified by the endorsement policy) and then finally delivered to the committer peers to append the new values in the chain and update the world state. Data is only written in the chain after it passes all the validations and hence an orderer can never deny for the changes made in the data.
I found another reason for this delay.
The batchtimeout variable in configtx.yaml is set to 2 seconds. So it will do its processing and then wait for 2 seconds and then cut a block. So for write operation it takes approximately 2.5 seconds.

Can I get an example that check 'Endorsement Policy' in node.js application?

I read below statement from 'Transaction Flow' chapter of hyperledger-fabric docs.
( https://hyperledger-fabric.readthedocs.io/en/latest/txflow.html )
If the client application intends to submit the transaction to Ordering Service to update the ledger, the application determines if the specified endorsement policy has been fulfilled before submitting
Does the 'Endorsement Policy' means endorsement policy for chaincode that can be specified in the CLI?
( c.f. -P "OR ('Org1MSP.member','Org2MSP.member')" )
If so, can I get an example that check 'Endorsement Policy' in node.js application?
Thank you.
Check for consistency of endorsements is already part of the SDK, so it should be transparent for the client code, please take a look on Channel.js:
var endorsements = [];
let proposalResponse = proposalResponses;
if(Array.isArray(proposalResponses)) {
for(let i=0; i<proposalResponses.length; i++) {
// make sure only take the valid responses to set on the consolidated response object
// to use in the transaction object
if (proposalResponses[i].response && proposalResponses[i].response.status === 200) {
proposalResponse = proposalResponses[i];
endorsements.push(proposalResponse.endorsement);
}
}
} else {
if (proposalResponse && proposalResponse.response && proposalResponse.response.status === 200) {
endorsements.push(proposalResponse.endorsement);
}
}
if(endorsements.length < 1) {
logger.error('sendTransaction - no valid endorsements found');
return Promise.reject(new Error('no valid endorsements found'));
}
Now this code checks that it got consistent endorsement response from all endorsement peers request has been sent to.
While it's up to the client application logic to ensure whenever it has satisfiable set of endorsement signatures. E.g. if endorsement policy is
AND(OR(Org1.member, Org3.member), OR(Org2.member, Org3.member))
and you got signatures only of org1 and org2, the above check will pass, while application has to be aware of endorsement rule and understand that responses of org1 and org2 alone is not enough and need to get also endorsement from org3.
With upcoming versions of Fabric, most likely v1.2 there will be service discovery capabilities where application will be provide capabilities to automatically detect satisfiable subsets of endorsing peers, making this part easier for app developer.

Resources