While submitting transaction no ledger context error in hyperledger chaincode - hyperledger-fabric

I am converting a certificate signing request to self signed certificate using hyper ledger chaincode. But while storing information regarding the certificate, transaction is not being successful and it gives me no ledger context error.
Nodejs version : 8.9.4
My chaincode function is:
async registerDomain(ctx, csr) {
let buff = new Buffer(csr, 'base64')
let csrData = buff.toString('ascii')
pem.createPrivateKey(2048, {
aes128: "11223344"
}, async function (err, pk) {
let domain = new Domain(ctx, "abcd", "data.detail", "keys.certificate", "pk.key");
await ctx.stub.putState(domain.domainId, Buffer.from(JSON.stringify(domain)));
});
While transaction this is what I am getting inside peer docker logs:
HandleTransaction -> ERRO 09f [ddc81d1b] Failed to handle PUT_STATE. error: no ledger context
runtime.goexit
/opt/go/src/runtime/asm_amd64.s:1333
PUT_STATE failed: transaction ID: ddc81d1bcb69eecd6c6bbcf85ba16b2168486d4b232ef3c03fe5bbc7bb2adea1
github.com/hyperledger/fabric/core/chaincode.
runtime.goexit
Any help would be much appreciated.

I have also faced a similar issue. Though there is no any proper solution for this error.
As per my understanding, this error is thrown when tx takes more time to complete and lose the context instance provided by state db api's.
In your example, createPrivateKey might be taking more time to generate pk and thus causing "no ledger context" issue.
Reference:
https://jira.hyperledger.org/browse/FAB-17512?focusedCommentId=69269&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-69269

Related

ENDORSEMENT_POLICY_FAILURE while invoking chain code using even if the transaction object contains enough endorsements

I have a network on hyperledger fabric 1.4.4 with 5 organizations A , B, C , D , E. I created a channel with these 5 orgs and installed my chaincode on org A and org B because only they are apart of the endorsement policy.
This is the endorsement policy :
{"identities":[{"role":{"name":"member","mspId":"AMSP"}},{"role":{"name":"member","mspId":"BMSP"}},{"role":{"name":"member","mspId":"CMSP"}},{"role":{"name":"member","mspId":"DMSP"}},{"role":{"name":"member","mspId":"EMSP"}}],"policy":{"2-of":[{"signed-by":0},{"signed-by":1}]}}
I am using a gateway with the below configuration to invoke the chain code
const walletPath = path.join('wallet' );
const wallet = new FileSystemWallet(walletPath);
let connectionOptions = {
identity: userName,
wallet: wallet,
discovery: { enabled:true, asLocalhost: true },
eventHandlerOptions: {
commitTimeout: 100,
strategy: DefaultEventHandlerStrategies.NETWORK_SCOPE_ALLFORTX
}
};
logger.debug('Connecting to Fabric gateway');
await gateway.connect(clientConnectionProfileJson, connectionOptions);
const network = await gateway.getNetwork(channelName);
const contract = await network.getContract(chaincodeName , contractName);
const transaction = contract.createTransaction(functionName);
await transaction.submit(<arguments>);
This is the error which I a getting , at the client level
2021-02-17T05:28:13.063Z - warn: [TransactionEventHandler]: _strategyFail: strategy fail for transaction "9be4da8b1d52ddde804d6c7c08d134ef4b6ac2043cbe0258b5b4c921424c9f04": TransactionError: Peer a-org-peer1.a-org.com:7051 has rejected transaction "9be4da8b1d52ddde804d6c7c08d134ef4b6ac2043cbe0258b5b4c921424c9f04" with code "ENDORSEMENT_POLICY_FAILURE"
This is what I see in all the peer logs
2021-02-17 05:28:12.313 UTC [vscc] Validate -> ERRO 0db VSCC error: stateBasedValidator.Validate failed, err validation of endorsement policy for chaincode {chaincodeName} in tx 26:0 failed: signature set did not satisfy policy
After some research , I found that this is a failure that is occurring when the org peer is trying to commit the transaction to the ledger , and finds that the signature set did not satisfy the policy.
I have gone ahead and looked at the transaction object using the getTransactionByID method. I see that there are two endorsers MSP with the correct sign certificates , these certificates belong to the one of the peers of A and B orgs. So the discovery service correctly identified the peers and even the peers have endorsed the transaction , but not sure why the transaction is not getting committed.
What am I missing here ?
How can I verify if the signatures are correct ?
To explicitly say to the gateway that the request should go to specific endorsing peers , I have used the below code.
const walletPath = path.join('wallet' );
const wallet = new FileSystemWallet(walletPath);
let connectionOptions = {
identity: userName,
wallet: wallet,
discovery: { enabled: true , asLocalhost: true },
eventHandlerOptions: {
commitTimeout: 100,
strategy: DefaultEventHandlerStrategies.NETWORK_SCOPE_ALLFORTX
}
};
logger.debug('Connecting to Fabric gateway');
await gateway.connect(clientConnectionProfileJson, connectionOptions);
const network = await gateway.getNetwork(channelName);
const channel = network.getChannel();
let endorsingPeers = [];
endorsingPeers.push(channel.getChannelPeer('a-org-peer1.a-org.com'));
endorsingPeers.push(channel.getChannelPeer('b-org-peer1.b-org.com'));
// Get addressability to org.cargoesnetwork.ebilloflading contract
// Use chaincodeName that is used for installing
const contract = await network.getContract(chaincodeName , contractName);
const transaction = contract.createTransaction(functionName).setEndorsingPeers(endorsingPeers);
await transaction.submit(<arguments>);
No luck , the transaction still fails with the same endorsement policy failure. I verified the transaction object if the endorser sign certs are correctly present. They are present , but still got the same error.
Out of curiosity , I changed the endorsement policy to only one org from two orgs , every thing worked as expected. The issue exists only when the policy contains more than one endorsing organisations.
Please help in debugging this issue.
An ENDORSEMENT_POLICY_FAILURE can occur for a number of reasons. The first being you don't have enough signatures which is what you have said you have already checked. Another reason is that not all the signatures match to the proposal that was sent.
In the 1.4 gateway apis the proposals are received and not compared to see if they all match before a proposal is sent to the orderer. The SDK will send all the signatures and one of the proposals that was received back. The signatures are created over the each peer's individual proposal response.
If those proposals don't match (which would mean that your chaincode is not deterministic) then one of those signatures will be ok, but the other one won't because it won't match the proposal that was sent to the orderer.
I would check that your chaincode is deterministic because it's possible that each peer is generating different responses. An example of non-deterministic chaincode for example is where it creates a new date and stores that in the world state. Each peer would create a slightly different date value resulting in differing responses.

Hyperledger Fabric: timeout when sending proposal to peer

I have a problem with fabric 1.4 while using fabric-gateway-java. Sometimes, it throw TimeoutException when sending proposal to peers. In most cases, it works well. Can anyone help? thanks!
Here is the error log.
2020-09-03 10:02:34,202 [ERROR]--org.hyperledger.fabric.sdk.Channel 4451 -- Channel
Channel{id:1,name: mychannel} sending proposal with transaction
e1d7313d8f8fc09fbae9a3ac2027bbf33ba3714c028a609f26380a4b0810466e to
Peer{ id: 6, name: peer1.org1.example.com, channelName: mychannel,
url:grpcs://192.168.1.1:7051, mspid: Org1MSP} failed because of
timeout(35000 milliseconds) expiration
java.util.concurrent.TimeoutException: null
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:432)
at org.hyperledger.fabric.sdk.Channel.sendProposalToPeers(Channel.java:4434)
at org.hyperledger.fabric.sdk.Channel.sendProposal(Channel.java:4358)
at org.hyperledger.fabric.sdk.Channel.sendTransactionProposal(Channel.java:3908)
Actually I do not have any direct solution for your problem but I try to help you.
The problem is happened in "fabric-sdk-java" not in "fabric-gateway-java".
More specifically :
catch (TimeoutException e) {
message = format("Channel %s sending proposal with transaction %s to %s failed because of timeout(%d milliseconds) expiration",
toString(), txID, peerName, transactionContext.getProposalWaitTime());
logger.error(message, e);
}
Links: https://github.com/hyperledger/fabric-sdk-java/blob/master/src/main/java/org/hyperledger/fabric/sdk/Channel.java
For "fabric-sdk-java" you may follow this:
You may increase your setProposalWaitTime.
setProposalWaitTime
public void setProposalWaitTime(long proposalWaitTime)
Sets the timeout for a single proposal request to endorser in milliseconds.
Parameters:
proposalWaitTime - the timeout for a single proposal request to endorser in milliseconds
Links: https://javadoc.io/static/org.hyperledger.fabric-sdk-java/fabric-sdk-java/2.2.0/org/hyperledger/fabric/sdk/TransactionRequest.html#setProposalWaitTime-long-
So your code may look something like that:
TransactionProposalRequest request = fabClient.getInstance().newTransactionProposalRequest();
ChaincodeID ccid = ChaincodeID.newBuilder().setName(Config.CHAINCODE_1_NAME).build();
request.setChaincodeID(ccid);
request.setFcn("createCar");
String[] arguments = { "CAR1", "Chevy", "Volt", "Red", "Nick" };
request.setArgs(arguments);
request.setProposalWaitTime(4000);
For "fabric-gateway-java" you may follow this:
TimeoutException - If the transaction was successfully submitted to the orderer but timed out before a commit event was received from peers.
Links: https://hyperledger.github.io/fabric-gateway-java/master/org/hyperledger/fabric/gateway/Contract.html#createTransaction-java.lang.String-
So you may increase setCommitTimeout.
setCommitTimeout -Set the maximum length of time to wait for commit events to be received after submitting a transaction to the orderer.
Transaction setCommitTimeout(long timeout,
TimeUnit timeUnit)
Parameters:
timeout - the maximum time to wait.
timeUnit - the time unit of the timeout argument.
Returns:
this transaction object to allow method chaining.
Links: https://hyperledger.github.io/fabric-gateway-java/master/org/hyperledger/fabric/gateway/Transaction.html

Hyperledger Fabric - Update a channel config by adding a new Org

I am trying to add a new Org to an existing Hyperledger fabric network.
The initial network is created by the byfn.sh script that stands up an Orderer and Org1 & Org2.
I have followed this example on Medium.com to create the update protobuf file. Everything that requires configtxgen, cryptogen and configtxlator is done as per this example. However, when it comes to executing the command peer channel signconfigtx -f org3_update_in_envelope.pb, I would like to do that using the Fabric Node SDK.
A point to note here is that if I execute the peer channel ... commands from the cli container command line, the channel update goes through, so I know that the file org3_update_in_envelope.pb is not corrupted.
Using this tutorial and some guidance from this question, I have the following code:
let envelope_pb_file_name = '/tmp/' + json.msp + '_update_in_envelope.pb'; // the pb file we create using command line
let envelope_bytes = fs.readFileSync(envelope_pb_file_name);
if (envelope_bytes === undefined) {
throw new Error(`Could not read the protobuffer file ${envelope_pb_file_name}. Error`);
}
// have the nodeSDK extract out the config update
let config_update = client.extractChannelConfig(envelope_bytes);
let signature = client.signChannelConfig(config_update);
let signatures = [];
signatures.push(signature);
//let orderers = this.loanNetwork.getChannel().getOrderers();
let orderer, ordererName = "orderer.example.com:7050";
const ORDERER_URL = 'grpcs://localhost:7050';
const data = fs.readFileSync(SyndLoanConfig.chainconfig.networkpath + '/crypto-config/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem').toString();
orderer = client.newOrderer(ORDERER_URL,
{
'pem': Buffer.from(data).toString(),
'ssl-target-name-override': 'orderer.example.com'
});
let mspId = client.getMspid(); // mspId shows "OrdererMSP" after this call is executed
const keyPath = SyndLoanConfig.chainconfig.networkpath + '/crypto-config/ordererOrganizations/example.com/users/Admin#example.com/msp/keystore';
let keyFile, keyFileAry = fs.readdirSync(keyPath).filter(fn => fn.endsWith('_sk'));
for (let f of keyFileAry) {
keyFile = f;
break;
}
keyFile = path.join(keyPath,keyFile);
const keyPEM = fs.readFileSync(keyFile).toString();
const certPath = SyndLoanConfig.chainconfig.networkpath + '/crypto-config/ordererOrganizations/example.com/users/Admin#example.com/msp/signcerts';
let certFile, certFileAry = fs.readdirSync(certPath).filter(fn => fn.endsWith('.pem'));
for (let f of certFileAry) {
certFile = f;
break;
}
certFile = path.join(certPath,certFile);
const certPEM = fs.readFileSync(certFile).toString();
client.setAdminSigningIdentity(keyPEM, certPEM, "OrdererMSP");
if (orderer === undefined) {
throw new Error(`Could not find an orderer associated with channel ${orgJSON.channel}. Error.`)
}
let tx_id = client.newTransactionID();
let request = {
config: config_update, //the binary config
// envelope: envelope_bytes,
signatures: signatures, // the collected signatures
name: orgJSON.channel, // the channel name
orderer: orderer, //the orderer from above
txId: tx_id //the generated transaction id
};
let addOrgResult = await client.updateChannel(request);
addOrgResult variable shows the following error:
info: implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the 'Writers' sub-policies to be satisfied: permission denied
status: FORBIDDEN
Orderer logs show this:
2020-01-17 21:49:21.620 UTC [cauthdsl] deduplicate -> ERRO 057 Principal deserialization failure (MSP is unknown) for identity 0
2020-01-17 21:49:21.621 UTC [cauthdsl] deduplicate -> ERRO 058 Principal deserialization failure (MSP is unknown) for identity 0
2020-01-17 21:49:21.621 UTC [cauthdsl] deduplicate -> ERRO 059 Principal deserialization failure (MSP is unknown) for identity 0
2020-01-17 21:49:21.621 UTC [orderer.common.broadcast] ProcessMessage -> WARN 05a [channel: mychannel] Rejecting broadcast of config message from 192.168.208.1:56556 because of error: implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the 'Writers' sub-policies to be satisfied: permission denied
Going through Nikhil Gupta's helpful response to this question, it appears that this error is due to
The error before the policy warning, ERRO 021 Principal
deserialization failure (MSP SampleOrg is unknown) for identity 0,
indicates that the MSP ID that was passed as a parameter with the
request was not recognized by the ordering service. This could be a
result of passing the wrong MSP ID to the command. This error may also
indicate that your organization has not joined the consortium hosted
by the ordering service system channel. If you are updating an
application channel, this error could occur if your organization is
not yet a member of the channel you are trying to update.
However, I am not sure how to proceed because I have connected to the network (Gateway.connect) using the Admin#example.com identity. Additionally, I am also calling client.setAdminSigningIdentity(keyPEM, certPEM, "OrdererMSP"); before making the update.
Any help would be greatly appreciated. Thank you.
The default policy for updating a channel requires a majority, which in your case means you will need signatures from both Org1 admin and Org2 admin and then either Org1 or Org2 can send the actual config update to the orderer.
This means that you need to run
let config_update = client.extractChannelConfig(envelope_bytes);
let signature = client.signChannelConfig(config_update);
let signatures = [];
signatures.push(signature);
as both an Org1 admin and an Org2 admin.
You can then submit the transaction to the orderer as either an Org1 admin or an Org2 admin (but not as the Orderer admin).

Get MSPID from a command line request in chaincode

I'm currently trying to evaluate the requester MSPID to authorize a specific list of Members being able to request a function on chaincode, but when I ask for "stub.getCreator().mspId" it always give me "undefined"
I'm currently calling the function with command like via "docker exec". I checked that my transaction should be signed before to "getCreator" to work, but I don't know if it's possible to sign a transaction with a command line call.
My command line request is:
docker exec cli.example.com peer chaincode invoke -o orderer.example.com:7050 -C examplechannel -c '{"Args":["createVcc", "{ \"date\": 12345, \"reference\": \"anything\", \"serialNumber\": \"BR-12345\", \"presentedTo\": \"Example project\", \"quantity\": 22279 }"]}' -n example
The validation function:
const isAdmin = (func, creator) => {
if (!adminList.includes(creator)) {
throw new Error(`Organization ${creator} does not have access to perform function ${func}`);
}
}
Using validation function in chaincode:
async (stub, data) => {
...
isAdmin('createVcc', stub.getCreator().mspId);
...
}
And I'm receiving:
Error: endorsement failure during invoke. response: status:500 message:"transaction returned with failure: Organization undefined does not have access to perform function createVcc"
I expect to "getCreator().mspid" not to be undefined, anyone knows what could solve my question ?
Try below my code snippet
const ClientIdentity = require('fabric-shim').ClientIdentity;
let cid = new ClientIdentity(stub);
let mspID = cid.getMSPID()
let isAuthorized = false;
if (cid.assertAttributeValue('createVcc', mspID){
isAuthorized = true;
}
With Node chaincode (Smart Contract) you should be able to use the Client Identity object and then getMSPID() or getID()
If you use the New Programming Model - specifically the fabric-contract-api, then this includes the Client Identity object. Using this you can also check Attributes from the certificate allowing you more flexibility in your access control. There is a tutorial here and the latest Fabric Samples use the New Programming Model.
You might also like to consider using the beforeTransaction provided with the fabric-contract-api and use this as a place to do all your access control, checking function names and "IDs".

Hyperledger Fabric Error: 2 UNKNOWN: access denied: channel [mychannel] creator org [Org1MSP]

I'm trying to interact with the peers from JavaScript and I keep getting
{ Error: 2 UNKNOWN: access denied: channel [mychannel] creator org [Org1MSP]
at Object.exports.createStatusError (/blockchain-api-js/node_modules/grpc/src/common.js:87:15)
at Object.onReceiveStatus (/blockchain-api-js/node_modules/grpc/src/client_interceptors.js:1188:28)
at InterceptingListener._callNext (/blockchain-api-js/node_modules/grpc/src/client_interceptors.js:564:42)
at InterceptingListener.onReceiveStatus (/blockchain-api-js/node_modules/grpc/src/client_interceptors.js:614:8)
at callback (/blockchain-api-js/node_modules/grpc/src/client_interceptors.js:841:24)
code: 2,
metadata: [Object],
details: 'access denied: channel [mychannel] creator org [Org1MSP]' }
I'm using the fabric-ca sample and I was able to execute transactions from cli and from cli through run-fabric.sh but I can't seem to do that from JS, I've created a new user and set the client and cert with client.setTlsClientCertAndKey(cert, key);, I even tried giving the admin cert and key from /data/orgs/org1/admin/msp/signcerts, /data/orgs/org1/admin/msp/admincerts and /data/orgs/org1/admin/msp/keystore as well as the ones from /data/tls/ but with no luck
And this is the portion of the code I use:
var channel = this.client.newChannel('mychannel')
let serverCert = fs.readFileSync('/data/org0-ca-chain.pem');
channel.addOrderer(
this.client.newOrderer(
config.orderers['orderer1-org0'].url,
{
pem: Buffer.from(serverCert).toString()
}
)
);
serverCert = fs.readFileSync('/data/org1-ca-chain.pem');
const peer1 = this.client.newPeer(
config.peers['peer1-org1'].url,
{
pem: Buffer.from(serverCert).toString()
}
);
channel.addPeer(peer1);
this.eventhubs = []
this.eventhubs.push(channel.newChannelEventHub(peer1));
serverCert = fs.readFileSync('/data/org2-ca-chain.pem');
const peer2 = this.client.newPeer(
config.peers['peer1-org2'].url,
{
'pem': Buffer.from(serverCert).toString()
}
);
channel.addPeer(peer2);
this.eventhubs.push(channel.newChannelEventHub(peer2));
this.channel = channel;
console.log(this.channel)
return this.channel.sendTransactionProposal(request);
Is there something wrong with my code or the way I do it? Can someone tell me what I am doing wrong? I've seen a few similar questions but those happened when composer was used mostly and I couldn't fix my problem with the answers from there,
You'd better check the user context of client I think.
user context has mspID. check whether mspId is Org1MSP or not.
The error could be because of the Certificates to sign the transaction.Double check your certificate received from CA and also checked the certificates and path used inside the docker container of peers.

Resources