1

First, we are quite new in the area Hyperledger Fabric and MQTT. We are building a prototype with a Blockchain platform (Hyperledger Fabric) written in nodeJS and a raspberry pi for transmitting the IoT data (working with mqtt). In our nodeJS file we create a MQTT client that subscribes to a topic and gets as a message a JSON object. The parameters of that object have to be passed on to the smart contract (submitContract). We realized that the gateway for Hyperledger Fabric disconnects before it runs the MQTT event functions (client.on) and therefore we thought we let the gateway disconnect on the condition of a submitted contract (see below code). In order to do so we want to get the success variable out of the client.on("message") function so that we can use it for the if statement at the end. However, the success variable doesn't seem to get updated to success=true by simply using return within client.on() so that eventually the program never exits (aka gateway is not disconnected). Below, you see parts of the code (the relevant parts). Does anyone know how to pass on properly an updated variable out of the MQTT event function?

'use strict';

const { FileSystemWallet, Gateway } = require('fabric-network');
const mqtt = require("mqtt");

async function main() {
    try {
        // Create a new gateway for connecting to our peer node.
        const gateway = new Gateway();
        await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: true } });

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

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

        //MQTT client connection & contract submission

        console.log("connecting to broker");
        const client = mqtt.connect("mqtt://192.168.43.217");
        var success = false;

        client.on("connect", () =>{
            console.log("Subscribing");
            client.subscribe("rfidData");
            console.log("Please hold your tag on the RFID reader. Wait...");
        });

        client.on("message", (topic, message) =>{
            var rfidPayload = JSON.parse(message.toString());
            var carKeyIn = rfidPayload.carKey;
            var renterIDIn = rfidPayload.renterID;
            var timestampIn = rfidPayload.timestamp;
            console.log(rfidPayload);

            contract.submitTransaction('openCar', carKeyIn, renterIDIn, timestampIn);
            success = true;
            console.log("Success? " + success);
            return success;
        });

        client.stream.on('error', (err) => {
            console.log('errorMessage', err);
            client.end()
        });       

        client.on("offline",() =>{
            console.log("offline");
        });

        client.on("reconnect", ()=>{
            console.log("reconnect");
        });

        // Disconnect from the gateway.
        if (success === true){
            client.end();
            gateway.disconnect();
        };

    } catch (error) {
        console.error(`Failed to submit transaction: ${error}`);
        process.exit(1);
    }
}

main();
Mohammad Faisal
  • 2,144
  • 15
  • 26

1 Answers1

0

You need to take on the concept of asynchronous execution and event driven systems. The application you have written does not execute in the order it is written.

The on('message',....) call back will only be executed when a message is delivered to client. This function also does not return any values (it is not actually called by any of your code, it is called by the underlying MQTT client code) so it will not "return" the value of success.

If you want the application to disconnect after it has received the first message then the easiest thing to do is to move the code that disconnects the MQTT client and the Fabric gateway to inside the callback. e.g.

client.on("message", (topic, message) =>{
  var rfidPayload = JSON.parse(message.toString());
  var carKeyIn = rfidPayload.carKey;
  var renterIDIn = rfidPayload.renterID;
  var timestampIn = rfidPayload.timestamp;
  console.log(rfidPayload);

  contract.submitTransaction('openCar', carKeyIn, renterIDIn, timestampIn);

  gateway.disconnect();
  client.end();
});

EDIT: Looking at the doc it appears that submitTransaction() is flagged as being an async function, so you should be able to use await to block until it completes

  ...
  console.log(rfidPayload);

  await contract.submitTransaction('openCar', carKeyIn, renterIDIn, timestampIn);

  gateway.disconnect();
  client.end();
});
hardillb
  • 54,545
  • 11
  • 67
  • 105
  • Hey hardillb. Thanks for the input but we already tried that and the problem is that the client disconnects before being able to submit the Transaction. So the following steps work `connecting to broker` `Subscribing` `Please hold your tag on the RFID reader. Wait...` `{ carKey: 'CAR1', renterID: '863881349114', timestamp: '09 Mar 2020 08:30:27' }` Then we receive the error message `(node:8441) UnhandledPromiseRejectionWarning: Error: Cannot createCall with a closed Channel` – Sophia Nagler Mar 09 '20 at 08:41
  • Does `contract.submitTransaction()` return a promise? – hardillb Mar 09 '20 at 08:43