node.jsjsonhyperledger-fabrichyperledgerhyperledger-chaincode

SyntaxError: Unexpected end of JSON input when trying to query transaction details from the hyperledger 2.2


I am trying to run a rewards example on .hyperledger 2.2. The contract is successfully packaged and deployed. I was also able to run the application successfully and enroll admin and user.

Chaincode successfully deployed :

Committed chaincode definition for chaincode 'customerloyalty' on channel 'mychannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
Query chaincode definition successful on peer0.org2 on channel 'mychannel'

Enroll admin successfully :

 
Wallet path: ../fabric-samples/asset-transfer-basic/application-customerloyalty/wallet
Successfully enrolled admin user "admin" and imported it into the wallet

was able to successfully register user :

app running on port: 8000
Using param - firstname: Test lastname: User email: test@example.com phonenumber: 111-111-1111 accountNumber: 123456 cardId: 123
Valid Entries
Wallet path: ../fabric-samples/asset-transfer-basic/application-customerloyalty/wallet
Successfully registered and enrolled admin user 123 and imported it into the wallet
admin user admin disconnected

Submit Create Member transaction.
createMemberResponse: 
{
  accountNumber: '123456',
  firstName: 'Test',
  lastName: 'User',
  email: 'test@example.com',
  phoneNumber: '111-111-1111',
  points: 0
}

Get member state 
memberResponse.parse_response: 
{
  accountNumber: '123456',
  firstName: 'Test',
  lastName: 'User',
  email: 'test@example.com',
  phoneNumber: '111-111-1111',
  points: 0
}
memberData using param -  accountNumber: 123456 cardId: 123
Wallet path: ../fabric-samples/asset-transfer-basic/application-customerloyalty/wallet

Get member state 
{
  accountNumber: '123456',
  firstName: 'Test',
  lastName: 'User',
  email: 'test@example.com',
  phoneNumber: '111-111-1111',
  points: 0
}
Wallet path: ../fabric-samples/asset-transfer-basic/application-customerloyalty/wallet

However, when I try to get transaction information in the app I get the following error with no response from peers :

Get use points transactions state for member 123456
2023-01-05T21:28:46.042Z - error: [Transaction]: Error: No valid responses from any peers. Errors:
    peer=peer0.org1.example.com:7051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    peer=peer0.org2.example.com:9051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    at newEndorsementError (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:74:12)
    at getResponsePayload (/../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:41:23)
    at Transaction.submit (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:255:28)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.usePointsTransactionsInfo (../fabric-samples/asset-transfer-basic/application-customerloyalty/network/network.js:592:41)
Error: No valid responses from any peers. Errors:
    peer=peer0.org1.example.com:7051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    peer=peer0.org2.example.com:9051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    at newEndorsementError (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:74:12)
    at getResponsePayload (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:41:23)
    at Transaction.submit (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:255:28)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.usePointsTransactionsInfo (../fabric-samples/asset-transfer-basic/application-customerloyalty/network/network.js:592:41) {
  responses: [
    {
      version: 0,
      timestamp: null,
      response: [Object],
      payload: <Buffer >,
      endorsement: null,
      connection: [Object],
      peer: 'peer0.org1.example.com:7051'
    },
    {
      version: 0,
      timestamp: null,
      response: [Object],
      payload: <Buffer >,
      endorsement: null,
      connection: [Object],
      peer: 'peer0.org2.example.com:9051'
    }
  ],
  errors: []
}
Wallet path: ../fabric-samples/asset-transfer-basic/application-customerloyalty/wallet

Get earn points transactions state for member 123456
2023-01-05T21:28:46.192Z - error: [Transaction]: Error: No valid responses from any peers. Errors:
    peer=peer0.org1.example.com:7051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    peer=peer0.org2.example.com:9051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    at newEndorsementError (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:74:12)
    at getResponsePayload (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:41:23)
    at Transaction.submit (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:255:28)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.earnPointsTransactionsInfo (../fabric-samples/asset-transfer-basic/application-customerloyalty/network/network.js:545:25)
Error: No valid responses from any peers. Errors:
    peer=peer0.org1.example.com:7051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    peer=peer0.org2.example.com:9051, status=500, message=error in simulation: transaction returned with failure: SyntaxError: Unexpected end of JSON input
    at newEndorsementError (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:74:12)
    at getResponsePayload (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:41:23)
    at Transaction.submit (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/fabric-network/lib/transaction.js:255:28)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.earnPointsTransactionsInfo (../fabric-samples/asset-transfer-basic/application-customerloyalty/network/network.js:545:25) {
  responses: [
    {
      version: 0,
      timestamp: null,
      response: [Object],
      payload: <Buffer >,
      endorsement: null,
      connection: [Object],
      peer: 'peer0.org1.example.com:7051'
    },
    {
      version: 0,
      timestamp: null,
      response: [Object],
      payload: <Buffer >,
      endorsement: null,
      connection: [Object],
      peer: 'peer0.org2.example.com:9051'
    }
  ],
  errors: []
}
node:internal/errors:484
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:393:5)
    at ServerResponse.setHeader (node:_http_outgoing:644:11)
    at ServerResponse.header (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/express/lib/response.js:794:10)
    at ServerResponse.send (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/express/lib/response.js:174:12)
    at ServerResponse.json (../fabric-samples/asset-transfer-basic/application-customerloyalty/node_modules/express/lib/response.js:278:15)
    at ../fabric-samples/asset-transfer-basic/application-customerloyalty/app.js:278:37
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

the above log indicates that json syntax is not correct in network.js file both invoking submitTransaction function. excerpt from Network.js file is :

  /*
  * Get all EarnPoints transactions data
  * @param {String} cardId Card id to connect to network
  */
    earnPointsTransactionsInfo: async function (cardId, userType, userId) {

        // Create a new file system based wallet for managing identities.
        const walletPath = path.join(process.cwd(), '/wallet');
        const wallet = await Wallets.newFileSystemWallet(walletPath);
        console.log(`Wallet path: ${walletPath}`);

        try {
            // Create a new gateway for connecting to our peer node.
            const gateway2 = new Gateway();
            await gateway2.connect(ccp, { wallet, identity: cardId, discovery: gatewayDiscovery });

            // Get the network (channel) our contract is deployed to.
            const network = await gateway2.getNetwork('mychannel');

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

            console.log(`\nGet earn points transactions state for ${userType} ${userId}`);
            //for debug only
            console.log(await contract.submitTransaction('EarnPointsTransactionsInfo', 'userType', 'userId'));
            //
            let earnPointsTransactions = await contract.submitTransaction('EarnPointsTransactionsInfo', userType, userId);
            //for debug only
            console.log(await contract.submitTransaction('EarnPointsTransactionsInfo', userType, userId));
            //
            earnPointsTransactions = JSON.parse(earnPointsTransactions.toString());
            console.log(earnPointsTransactions);

            // Disconnect from the gateway.
            await gateway2.disconnect();

            return earnPointsTransactions;
        }
        catch(err) {
            //print and return error
            console.log(err);
            let error = {};
            error.error = err.message;
            return error;
        }

    },
    usePointsTransactionsInfo: async function (cardId, userType, userId) {

        // Create a new file system based wallet for managing identities.
        const walletPath = path.join(process.cwd(), '/wallet');
        const wallet = await Wallets.newFileSystemWallet(walletPath);
        console.log(`Wallet path: ${walletPath}`);

        try {
            // Create a new gateway for connecting to our peer node.
            const gateway2 = new Gateway();
            await gateway2.connect(ccp, { wallet, identity: cardId, discovery: gatewayDiscovery });

            // Get the network (channel) our contract is deployed to.
            const network = await gateway2.getNetwork('mychannel');

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

            console.log(`\nGet use points transactions state for ${userType} ${userId}`);
            let usePointsTransactions = await contract.submitTransaction('UsePointsTransactionsInfo',userType, userId);
            usePointsTransactions = JSON.parse(usePointsTransactions.toString());
            console.log(usePointsTransactions);

            // Disconnect from the gateway.
            await gateway2.disconnect();

            return usePointsTransactions;
        }

I have tried to check logs from the peer using docker logs <container name> :

2023-01-05 22:28:46 2023-01-05T21:28:46.023Z error [c-api:contracts-spi/chaincodefromcontract.js]     [mychannel-fedc897c] SyntaxError: Unexpected end of JSON input  
2023-01-05 22:28:46 2023-01-05T21:28:46.033Z error [c-api:lib/handler.js]                             [mychannel-fedc897c] Calling chaincode Invoke() returned error response [SyntaxError: Unexpected end of JSON input
2023-01-05 22:28:46     at JSON.parse (<anonymous>)
2023-01-05 22:28:46     at CustomerLoyalty.UsePointsTransactionsInfo (/usr/local/src/lib/customerloyalty.js:110:29)
2023-01-05 22:28:46     at processTicksAndRejections (node:internal/process/task_queues:96:5)
2023-01-05 22:28:46     at async ChaincodeFromContract.invokeFunctionality (/usr/local/src/node_modules/fabric-shim/lib/contract-spi/chaincodefromcontract.js:378:32)
2023-01-05 22:28:46     at async handleMessage (/usr/local/src/node_modules/fabric-shim/lib/handler.js:602:24)]. Sending ERROR message back to peer  
2023-01-05 22:28:46 2023-01-05T21:28:46.181Z error [c-api:contracts-spi/chaincodefromcontract.js]     [mychannel-644303c3] SyntaxError: Unexpected end of JSON input  
2023-01-05 22:28:46 2023-01-05T21:28:46.184Z error [c-api:lib/handler.js]                             [mychannel-644303c3] Calling chaincode Invoke() returned error response [SyntaxError: Unexpected end of JSON input
2023-01-05 22:28:46     at JSON.parse (<anonymous>)
2023-01-05 22:28:46     at CustomerLoyalty.EarnPointsTransactionsInfo (/usr/local/src/lib/customerloyalty.js:89:29)
2023-01-05 22:28:46     at processTicksAndRejections (node:internal/process/task_queues:96:5)
2023-01-05 22:28:46     at async ChaincodeFromContract.invokeFunctionality (/usr/local/src/node_modules/fabric-shim/lib/contract-spi/chaincodefromcontract.js:378:32)
2023-01-05 22:28:46     at async handleMessage (/usr/local/src/node_modules/fabric-shim/lib/handler.js:602:24)]. Sending ERROR message back to peer  
2023-01-05 22:32:51 2023-01-05T21:32:51.616Z info [c-api:lib/handler.js]                              [mychannel-68bdfcd2] Calling chaincode Invoke() succeeded. Sending COMPLETED message back to peer  
2023-01-05 22:32:53 2023-01-05T21:32:53.977Z error [c-api:contracts-spi/chaincodefromcontract.js]     [mychannel-7f185a49] SyntaxError: Unexpected end of JSON input  
2023-01-05 22:32:53 2023-01-05T21:32:53.989Z error [c-api:lib/handler.js]                             [mychannel-7f185a49] Calling chaincode Invoke() returned error response [SyntaxError: Unexpected end of JSON input
2023-01-05 22:32:53     at JSON.parse (<anonymous>)
2023-01-05 22:32:53     at CustomerLoyalty.UsePointsTransactionsInfo (/usr/local/src/lib/customerloyalty.js:110:29)
2023-01-05 22:32:53     at processTicksAndRejections (node:internal/process/task_queues:96:5)
2023-01-05 22:32:53     at async ChaincodeFromContract.invokeFunctionality (/usr/local/src/node_modules/fabric-shim/lib/contract-spi/chaincodefromcontract.js:378:32)
2023-01-05 22:32:53     at async handleMessage (/usr/local/src/node_modules/fabric-shim/lib/handler.js:602:24)]. Sending ERROR message back to peer  
2023-01-05 22:32:54 2023-01-05T21:32:54.195Z error [c-api:contracts-spi/chaincodefromcontract.js]     [mychannel-44d04ba9] SyntaxError: Unexpected end of JSON input  
2023-01-05 22:32:54 2023-01-05T21:32:54.197Z error [c-api:lib/handler.js]                             [mychannel-44d04ba9] Calling chaincode Invoke() returned error response [SyntaxError: Unexpected end of JSON input
2023-01-05 22:32:54     at JSON.parse (<anonymous>)
2023-01-05 22:32:54     at CustomerLoyalty.EarnPointsTransactionsInfo (/usr/local/src/lib/customerloyalty.js:89:29)
2023-01-05 22:32:54     at processTicksAndRejections (node:internal/process/task_queues:96:5)
2023-01-05 22:32:54     at async ChaincodeFromContract.invokeFunctionality (/usr/local/src/node_modules/fabric-shim/lib/contract-spi/chaincodefromcontract.js:378:32)
2023-01-05 22:32:54     at async handleMessage (/usr/local/src/node_modules/fabric-shim/lib/handler.js:602:24)]. Sending ERROR message back to peer  

Here is the smart contract script customerloyalty.js :

'use strict';

const { Contract } = require('fabric-contract-api'); const allPartnersKey = 'all-partners'; const earnPointsTransactionsKey = 'earn-points-transactions'; const usePointsTransactionsKey = 'use-points-transactions';

class CustomerLoyalty extends Contract {
// Init function executed when the ledger is instantiated
async instantiate(ctx) {
    console.info('============= START : Initialize Ledger ===========');

    await ctx.stub.putState('instantiate', Buffer.from('INIT-LEDGER'));
    await ctx.stub.putState(allPartnersKey, Buffer.from(JSON.stringify([])));
    await ctx.stub.putState(earnPointsTransactionsKey, Buffer.from(JSON.stringify([])));
    await ctx.stub.putState(usePointsTransactionsKey, Buffer.from(JSON.stringify([])));

    console.info('============= END : Initialize Ledger ===========');
}

// Add a member on the ledger
async CreateMember(ctx, member) {
    member = JSON.parse(member);

    await ctx.stub.putState(member.accountNumber, Buffer.from(JSON.stringify(member)));

    return JSON.stringify(member);
}

// Add a partner on the ledger, and add it to the all-partners list
async CreatePartner(ctx, partner) {
    partner = JSON.parse(partner);

    await ctx.stub.putState(partner.id, Buffer.from(JSON.stringify(partner)));

    let allPartners = await ctx.stub.getState(allPartnersKey);
    allPartners = JSON.parse(allPartners);
    allPartners.push(partner);
    await ctx.stub.putState(allPartnersKey, Buffer.from(JSON.stringify(allPartners)));

    return JSON.stringify(partner);
}

// Record a transaction where a member earns points
async EarnPoints(ctx, earnPoints) {
    earnPoints = JSON.parse(earnPoints);
    earnPoints.timestamp = new Date((ctx.stub.txTimestamp.seconds.low*1000)).toGMTString();
    earnPoints.transactionId = ctx.stub.txId;

    let member = await ctx.stub.getState(earnPoints.member);
    member = JSON.parse(member);
    member.points += earnPoints.points;
    await ctx.stub.putState(earnPoints.member, Buffer.from(JSON.stringify(member)));

    let earnPointsTransactions = await ctx.stub.getState(earnPointsTransactionsKey);
    earnPointsTransactions = JSON.parse(earnPointsTransactions);
    earnPointsTransactions.push(earnPoints);
    await ctx.stub.putState(earnPointsTransactionsKey, Buffer.from(JSON.stringify(earnPointsTransactions)));

    return JSON.stringify(earnPoints);
}

// Record a transaction where a member redeems points
async UsePoints(ctx, usePoints) {
    usePoints = JSON.parse(usePoints);
    usePoints.timestamp = new Date((ctx.stub.txTimestamp.seconds.low*1000)).toGMTString();
    usePoints.transactionId = ctx.stub.txId;

    let member = await ctx.stub.getState(usePoints.member);
    member = JSON.parse(member);
    if (member.points < usePoints.points) {
        throw new Error('Member does not have sufficient points');
    }
    member.points -= usePoints.points;
    await ctx.stub.putState(usePoints.member, Buffer.from(JSON.stringify(member)));

    let usePointsTransactions = await ctx.stub.getState(usePointsTransactionsKey);
    usePointsTransactions = JSON.parse(usePointsTransactions);
    usePointsTransactions.push(usePoints);
    await ctx.stub.putState(usePointsTransactionsKey, Buffer.from(JSON.stringify(usePointsTransactions)));

    return JSON.stringify(usePoints);
}

// Get earn points transactions of the particular member or partner
async EarnPointsTransactionsInfo(ctx, userType, userId) {
    let transactions = await ctx.stub.getState(earnPointsTransactionsKey);
    transactions = JSON.parse(transactions);
    let userTransactions = [];

    for (let transaction of transactions) {
        if (userType === 'member') {
            if (transaction.member === userId) {
                userTransactions.push(transaction);
            }
        } else if (userType === 'partner') {
            if (transaction.partner === userId) {
                userTransactions.push(transaction);
            }
        }
    }

    return JSON.stringify(userTransactions);
}

// Get use points transactions of the particular member or partner
async UsePointsTransactionsInfo(ctx, userType, userId) {
    let transactions = await ctx.stub.getState(usePointsTransactionsKey);
    transactions = JSON.parse(transactions);
    let userTransactions = [];

    for (let transaction of transactions) {
        if (userType === 'member') {
            if (transaction.member === userId) {
                userTransactions.push(transaction);
            }
        } else if (userType === 'partner') {
            if (transaction.partner === userId) {
                userTransactions.push(transaction);
            }
        }
    }

    return JSON.stringify(userTransactions);
}

// get the state from key
async GetState(ctx, key) {
    let data = await ctx.stub.getState(key);

    let jsonData = JSON.parse(data.toString());
    return JSON.stringify(jsonData);
}

module.exports = CustomerLoyalty;`

it seems that there is an syntax error with json.stringify. I don't know what to do next, or how to solve this. Any ideas?


Solution

  • I suspect that you have never invoked your instantiate transaction function and so the earnPointsTransactionsKey ledger key contains no data:

    % node --eval="JSON.parse(Buffer.from(''))"
    
    SyntaxError: Unexpected end of JSON input
        at JSON.parse (<anonymous>)
    

    Rather than relying on an initialize transaction to set effectively empty initial state, you might consider a helper function in your smart contract, something like this:

    async getEarnPointsTransactions(ctx) {
        const data = await ctx.stub.getState(earnPointsTransactionsKey);
        if (!data || data.length === 0) {
            return [];
        }
    
        return JSON.parse(data);
    }
    

    Also consider that all of your transactions that update the ledger are modifying the value of the earnPointsTransactionsKey ledger key. This is going to introduce contention as load increases and you are likely to experience MVCC_READ_CONFLICT failures as transactions concurrently update this state. These failures can be mitigated by implementing submit retry logic in your client application. You might consider different implementation approaches, such as:

    1. using composite keys to partition the data.
    2. using key history to read data associated with previous transactions.