Search code examples
node.jshyperledger-fabricblockchainhyperledger

Hyperledger Fabric 2.3 Error: Failed to connect before the deadline on Endorser- name:


Whenever I am trying to execute a transaction through NodeJS I am getting the error.

2021-02-12T09:33:58.302Z - error: [ServiceEndpoint]: Error: Failed to connect before the deadline on Endorser- name: peer1.peers.org1.com, url:grpcs://xxx.xxx.xxx.xxx:7051, connected:false, connectAttempted:true
2021-02-12T09:33:58.303Z - error: [ServiceEndpoint]: waitForReady - Failed to connect to remote gRPC server peer1.peers.org1.com url:grpcs://xxx.xxx.xxx.xxx:7051 timeout:3000
2021-02-12T09:33:58.306Z - info: [NetworkConfig]: buildPeer - Unable to connect to the endorser peer1.peers.org1.com due to Error: Failed to connect before the deadline on Endorser- name: peer1.peers.org1.com, url:grpcs://xxx.xxx.xxx.xxx:7051, connected:false, connectAttempted:true
    at checkState (/fabric23/node_modules/@grpc/grpc-js/build/src/client.js:69:26)
    at Timeout._onTimeout (/fabric23/node_modules/@grpc/grpc-js/build/src/channel.js:292:17)
    at listOnTimeout (internal/timers.js:549:17)
    at processTimers (internal/timers.js:492:7) {
  connectFailed: true
}
2021-02-12T09:34:01.308Z - error: [ServiceEndpoint]: Error: Failed to connect before the deadline on Endorser- name: peer1.peers.org2.com, url:grpcs://xxx.xxx.xxx.xxx:7051, connected:false, connectAttempted:true
2021-02-12T09:34:01.308Z - error: [ServiceEndpoint]: waitForReady - Failed to connect to remote gRPC server peer1.peers.org2.com url:grpcs://xxx.xxx.xxx.xxx:7051 timeout:3000
2021-02-12T09:34:01.309Z - info: [NetworkConfig]: buildPeer - Unable to connect to the endorser peer1.peers.org2.com due to Error: Failed to connect before the deadline on Endorser- name: peer1.peers.org2.com, url:grpcs://xxx.xxx.xxx.xxx:7051, connected:false, connectAttempted:true
    at checkState (/fabric23/node_modules/@grpc/grpc-js/build/src/client.js:69:26)
    at Timeout._onTimeout (/fabric23/node_modules/@grpc/grpc-js/build/src/channel.js:292:17)
    at listOnTimeout (internal/timers.js:549:17)
    at processTimers (internal/timers.js:492:7) {
  connectFailed: true
}
2021-02-12T09:34:04.314Z - error: [ServiceEndpoint]: Error: Failed to connect before the deadline on Endorser- name: peer1.peers.org3.com, url:grpcs://xxx.xxx.xxx.xxx:7051, connected:false, connectAttempted:true
2021-02-12T09:34:04.314Z - error: [ServiceEndpoint]: waitForReady - Failed to connect to remote gRPC server peer1.peers.org3.com url:grpcs://xxx.xxx.xxx.xxx:7051 timeout:3000
2021-02-12T09:34:04.315Z - info: [NetworkConfig]: buildPeer - Unable to connect to the endorser peer1.peers.org3.com due to Error: Failed to connect before the deadline on Endorser- name: peer1.peers.org3.com, url:grpcs://xxx.xxx.xxx.xxx:7051, connected:false, connectAttempted:true
    at checkState (/fabric23/node_modules/@grpc/grpc-js/build/src/client.js:69:26)
    at Timeout._onTimeout (/fabric23/node_modules/@grpc/grpc-js/build/src/channel.js:292:17)
    at listOnTimeout (internal/timers.js:549:17)
    at processTimers (internal/timers.js:492:7) {
  connectFailed: true
}
2021-02-12T09:34:07.317Z - error: [ServiceEndpoint]: Error: Failed to connect before the deadline on Committer- name: ord1.orderers.org1.com, url:grpcs://xxx.xxx.xxx.xxx:7050, connected:false, connectAttempted:true
2021-02-12T09:34:07.317Z - error: [ServiceEndpoint]: waitForReady - Failed to connect to remote gRPC server ord1.orderers.org1.com url:grpcs://xxx.xxx.xxx.xxx:7050 timeout:3000
2021-02-12T09:34:07.317Z - info: [NetworkConfig]: buildOrderer - Unable to connect to the committer ord1.orderers.org1.com due to Error: Failed to connect before the deadline on Committer- name: ord1.orderers.org1## Heading ##.com, url:grpcs://xxx.xxx.xxx.xxx:7050, connected:false, connectAttempted:true
    at checkState (/fabric23/node_modules/@grpc/grpc-js/build/src/client.js:69:26)
    at Timeout._onTimeout (/fabric23/node_modules/@grpc/grpc-js/build/src/channel.js:292:17)
    at listOnTimeout (internal/timers.js:549:17)
    at processTimers (internal/timers.js:492:7) {
  connectFailed: true
}
Failed to evaluate transaction: Error: Committer must be connectable

Here is my connection.json

{
    "name": "byfn",
    "version": "1.0.0",
    "client": {
        "organization": "ORG1",
        "connection": {
            "timeout": {
                "peer": {
                    "endorser": "10000"
                },
                "orderer": "10000"
            }
        }
    },
    "channels": {
        "supplychain": {
            "orderers": [
                "ord1.orderers.org1.com",
                "ord2.orderers.org1.com",
                "ord3.orderers.org1.com"
            ],
            "peers": {
                "peer1.peers.org2.com": {},
                "peer1.peers.org3.com": {},
                "peer1.peers.org1.com": {}
            }
        }
    },
    "organizations": {
        "ORG1": {
            "mspid": "ORG1",
            "peers": [
                "peer1.peers.org1.com",
                "peer2.peers.org1.com"
            ]
        }
    },
    "orderers": {
        "ord1.orderers.org1.com": {
            "url": "grpcs://xxx.xxx.xxx.xxx:7050",
            "grpcOptions": {
                "ssl-target-name-override": "ord1.orderers.org1.com",
                "request-timeout": 12000
            },
            "tlsCACerts": {
                "path": "ca.pem"
            }
        }
    },
    "peers": {
        "peer1.peers.org2.com": {
            "url": "grpcs://xxx.xxx.xxx.xxx:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.peers.org2.com",
                "request-timeout": 12000,
                "grpc.keepalive_time_ms": 600000
            },
            "tlsCACerts": {
                "path": "ca.pem"
            }
        },
        "peer1.peers.org3.com": {
            "url": "grpcs://xxx.xxx.xxx.xxx:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.peers.org3.com",
                "request-timeout": 12000,
                "grpc.keepalive_time_ms": 600000
            },
            "tlsCACerts": {
                "path": "ca.pem"
            }
        },
        "peer1.peers.org1.com": {
            "url": "grpcs://xxx.xxx.xxx.xxx:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.peers.org1.com",
                "request-timeout": 12000,
                "grpc.keepalive_time_ms": 600000
            },
            "tlsCACerts": {
                "path": "ca.pem"
            }
        }
    }
}

And here is my test.js

'use strict';

const { Wallets, Gateway } = require('fabric-network');
const fs = require('fs');
const path = require('path');

const ccpPath = path.resolve(__dirname,'test-connection.json');
const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
const ccp = JSON.parse(ccpJSON);


async function main(){
    try {
        // const walletPath = path.join(process.cwd(), 'wallet');
        const wallet = await Wallets.newFileSystemWallet('wallet');
        // console.log(`Wallet path: ${walletPath}`);

        // Check to see if we've already enrolled the user.
        const userExists = await wallet.get('usernew');
        const tlsExists = await wallet.get('tlsid');
        if (!userExists) {
            console.log('An identity for the user "usernew" does not exist in the wallet');
            return;
        }
        if (!tlsExists) {
            console.log('An identity for the user "tls" does not exist in the wallet');
            return;
        }
        console.log("Here");
        // Create a new gateway for connecting to our peer node.
        const gateway = new Gateway();
        await gateway.connect(ccp, { wallet, identity: 'usernew', discovery: { enabled: false, asLocalhost: false }, clientTlsIdentity: 'tlsid' });

        console.log("Here1");
        // Get the network (channel) our contract is deployed to.
        const network = await gateway.getNetwork('mychannel');

        console.log("Here2");
        //Get the channel object to fetch out peers
        const channel = network.getChannel();

        console.log("Here3");
        //Get peers for endorsement
        const org1Peer = channel.getPeer('peer1.peers.org1.com');
        console.log(org1Peer);
        const org2Peer = channel.getPeer('peer1.peers.org2.com');
        console.log(org2Peer);
        const org3Peer = channel.getPeer('peer1.peers.org3.com');
        console.log(org3Peer);


        // Get the contract from the network.
        const contract = network.getContract('mycontract');

        const result = await contract.createTransaction("transaction").setEndorsingPeers([org1Peer, org2Peer, org3Peer]).setTransient().submit(
            "key",
            "val1",
            "val2"
        );
        
        console.log(`Transaction has been evaluated, result is: ${result.toString()}`);

    } catch (error) {
        console.error(`Failed to evaluate transaction: ${error}`);
    }
}

main()

My network is deployed on a kubernetes cluster and the NodeJS container is on the same cluster. The IPs that I am using for the pods are the ClusterIPs of the peer and orderer pods. Also the certificates I am using are not Fabric generated certs, the certs have been created and signed using the CA of our organization and thus the crypto folder has a "tlsintermediatecerts" folder inside it. I have tried using the pem file from inside the "tlsca" folder and also the pem file from inside the "tlsintermediatecerts" folder for the tlsca path in the connection.json. But none have worked. Here is the directory structure of the crypto folder.

Also I have verified the certs by making curl requests to each of the peers and orderers and checked that the handshake completes.

C:.
├───peers.org1.com
│   └───users
│       ├───[email protected]
│       │   ├───msp
│       │   │   ├───admincerts
│       │   │   ├───cacerts
│       │   │   ├───intermediatecerts
│       │   │   ├───keystore
│       │   │   ├───signcerts
│       │   │   ├───tlscacerts
│       │   │   └───tlsintermediatecerts
│       │   └───tls
│       └───[email protected]
│           ├───msp
│           │   ├───admincerts
│           │   ├───cacerts
│           │   ├───intermediatecerts
│           │   ├───keystore
│           │   ├───signcerts
│           │   ├───tlscacerts
│           │   └───tlsintermediatecerts
│           └───tls
├───peers.org2.com
│   └───users
│       ├───[email protected]
│       │   ├───msp
│       │   │   ├───admincerts
│       │   │   ├───cacerts
│       │   │   ├───intermediatecerts
│       │   │   ├───keystore
│       │   │   ├───signcerts
│       │   │   ├───tlscacerts
│       │   │   └───tlsintermediatecerts
│       │   └───tls
│       └───[email protected]
│           ├───msp
│           │   ├───admincerts
│           │   ├───cacerts
│           │   ├───intermediatecerts
│           │   ├───keystore
│           │   ├───signcerts
│           │   ├───tlscacerts
│           │   └───tlsintermediatecerts
│           └───tls
└───peers.org3.com
    └───users
        ├───[email protected]
        │   ├───msp
        │   │   ├───admincerts
        │   │   ├───cacerts
        │   │   ├───intermediatecerts
        │   │   ├───keystore
        │   │   ├───signcerts
        │   │   ├───tlscacerts
        │   │   └───tlsintermediatecerts
        │   └───tls
        └───[email protected]
            ├───msp
            │   ├───admincerts
            │   ├───cacerts
            │   ├───intermediatecerts
            │   ├───keystore
            │   ├───signcerts
            │   ├───tlscacerts
            │   └───tlsintermediatecerts
            └───tls

Any help is appreciated.


Solution

  • Answering my question here. Based on @Gari Singh's answer above the certificate that you have to use in the "tlsCACerts" parameter in the connection.json file has to be created by combining the intermediate and root CA into a single file. The first block in the file should be the intermediate CA and the second block should be the root CA. This certificate chaining is required because the intermediate CA is signed by the root CA and the client should pass both so that they can be validated properly. Comprehensive explanation can be found here: https://www.thesslstore.com/blog/root-certificates-intermediate/

    The final thing that I was missing because of which I was getting the error "Failed to evaluate transaction: Error: Committer must be connectable" was that I was passing 3 orderers in the "channels" section of the config and only passing one of their details in the "orderers" section of the config. Adding the ip and other details for the other 2 orderers took care of that issue.