1

I have a Javascript frontend that passes records in a JSON to the backend via Express to be deployed to the blockchain (currently using Rinkeby) with truffle-hdwallet-provider. This appears to work perfectly, but I have a really nasty problem - if I send 19 rows to be deployed, the first 17 or 18 get sent nicely. I see the transaction hash and the receipts come soon after. So far so good, but thereafter, the first records are reposted. I tried playing around with timeout, but all that I managed to do was to stop the server responding after 120 seconds and only 18-19 contracts were deployed.

The relevant front end code is:

function importInvoiceData(event) {
    var input = event.target;
    console.log("File Path: "         + input);

    var reader = new FileReader();
    reader.onloadend = function(){
        var newLine=String.fromCharCode(13)+String.fromCharCode(10);
        var invoiceLines=reader.result.split(newLine);
        var numLines = invoiceLines.length;

        console.log("number of invoices: " + numLines);

        var myColumn="";

        var params =[]

        for (var i=1;i<numLines;i++)
            {
            myColumn = invoiceLines[i].split(",");

            var myVendorAddress = myColumn[1];
            var myClientAddress = myColumn[3];
            var myInvoiceID = myColumn[4];
            var myCurrCode = myColumn[5];
            // 25569 = 1/1/1970 start of Unix time
            var myInvoiceDate = (parseInt(myColumn[6])-25569)*86400;
            var myInvoiceAmount = parseInt(myColumn[7])*1000000;
            var myAmountPaid = parseInt(myColumn[8])*1000000;
            var myInvoiceBalance = parseInt(myColumn[9])*1000000;
            var myInsuredAmount = parseInt(myColumn[10])*1000000;
            var myPaymentDays = parseInt(myColumn[11]);
            var myConfirmed = myColumn[12];
            var myInsurerAddress = myColumn[13];                

            console.log("myinvoiceID + myInvoiceBalance: " + myInvoiceID + " " + myInvoiceBalance);

            if (myInvoiceID != "") // This avoids trying to load empty rows
                {

                params[i-1] = { 
                    vendorAddress:  myVendorAddress,
                    clientAddress:  myClientAddress,
                    insurerAddress: myInsurerAddress, 
                    invoiceID:      myInvoiceID,
                    currencyCode:   myCurrCode,
                    invoiceDate:    myInvoiceDate,
                    invoiceAmount:  myInvoiceAmount,
                    amountPaid:     myAmountPaid,
                    invoiceBalance: myInvoiceBalance,
                    insuredAmount:  myInsuredAmount,
                    paymentDays:    myPaymentDays,
                    confirmed:      myConfirmed
                  };

                console.log("params" + JSON.stringify(params[i-1]));              
                } // if (myClientID <> "")
            } // for (var i=1;i<numLines;i++)

            const strParams = JSON.stringify(params);

            console.log("strParams" + strParams);

            var xhr = new XMLHttpRequest();
            xhr.open("POST", "http://localhost:80/deploy_invoice", true);
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(strParams);

        }; // reader.onloadend = function(){
    reader.readAsText(input.files[0]);
    }; // function openInvoiceFile(event) {

and the backend code is:

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors')
const app = express();

// Enable all CORS requests 
app.use(cors());

// enable middleware
app.use(bodyParser.json())
app.use(express.json());

const Web3 = require("web3");
const HDWalletProvider = require("@truffle/hdwallet-provider");

require('dotenv').config();
const provider = new HDWalletProvider(process.env.MNEMONIC, process.env.INFURA_URL);

var contract    = require("@truffle/contract");

const platformArtifacts = require('./build/contracts/Platform.json');
var platformContract = contract(platformArtifacts);
platformContract.setProvider(provider);

const vendorArtifacts = require('./build/contracts/Vendor.json');
var vendorContract = contract(vendorArtifacts);
vendorContract.setProvider(provider);

app.use(bodyParser.urlencoded({ extended: true })); 

function convertStringX(myString, len)
    {
    console.log("my String = " + myString);
    var myBuffer = [];
    var temp = Buffer.from(myString);

    for (var i = 0; i < len; i++) { 
        // eliminate empty characters (different than spaces which are 0x20)
        if (i < myString.length)
            myBuffer.push(temp[i]);
        else
            myBuffer.push(0x0);         
        } 

    console.log(myBuffer);
    return myBuffer;
    }

var myPlatform;
const platformAddress = "0x...";

async function instantiatePlatform(deployedAddress) {
    myPlatform = await platformContract.at(deployedAddress);
    console.log("myPlatform address " + myPlatform.address);
    }

instantiatePlatform(platformAddress);

app.all('/', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
});

var whitelist = ['localhost:8080']
var corsOptionsDelegate = function (req, callback) {
    var corsOptions;
    if (whitelist.indexOf(req.header('Origin')) !== -1) {
        corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
    } else {
        corsOptions = { origin: false } // disable CORS for this request
    }
    callback(null, corsOptions) // callback expects two parameters: error and options
}

async function createInvoice(_VendorAddress, _InvoiceID, _InvoiceDate, _PaymentDays, _InvoiceAmount, _InsuredAmount, _AmountPaid, 
        _Confirmed, _InsurerAddress, _ClientAddress, _CurrCode)
    {
    var myVendor = await vendorContract.at(_VendorAddress);

    myVendor.makeInvoice(_InvoiceID, _InvoiceDate, _PaymentDays, _InvoiceAmount, _InsuredAmount, _AmountPaid, 
        _Confirmed, _InsurerAddress, _ClientAddress, _CurrCode, 
        { from:provider.getAddress() })
        .once('transactionHash', function(hash) {
            console.log("TxHash: " + hash);
        }).on('receipt', function(receipt) { console.log("receipt: " + JSON.stringify(receipt)); })
            .then(function(result) {
        }, function(error) {
            console.log(error);
        });

    } // async function createInvoice(_InvoiceID, _InvoiceDate, _PaymentDays, _InvoiceAmount, _InsuredAmount, _AmountPaid, _Confirmed, _InsurerAddress, _ClientAddress, _CurrCode)

app.post('/deploy_invoice', (req, res) => {

    var myInput=req.body;
    console.log("myInput "+ myInput.length+ " " +myInput[0].invoiceID);

    for (i=0;i<myInput.length;i++)  
        {
        // Only add record if invoice is non-empty
        if (myInput[i].invoiceID != null && myInput[i].invoiceID != "")
            {
            var myVendorAddress = myInput[i].vendorAddress;
            var myClientAddress = myInput[i].clientAddress;
            var myInsurerAddress = myInput[i].insurerAddress;
            var myInvoiceID = myInput[i].invoiceID;
            myInvoiceID = convertStringX(myInvoiceID, 16);
            console.log("myInvoiceID "+ myInvoiceID);
            var myCurrCode = myInput[i].currencyCode;
            myCurrCode = convertStringX(myCurrCode, 3);
            console.log("myCurrCode "+ myCurrCode);
            var myInvoiceDate = myInput[i].invoiceDate;
            console.log("myInvoiceDate "+ myInvoiceDate);
            var myInvoiceAmount = myInput[i].insuredAmount;
            console.log("myInvoiceAmount "+ myInvoiceAmount);
            var myAmountPaid = myInput[i].amountPaid;
            console.log("myAmountPaid "+ myAmountPaid);
            var myInvoiceBalance = myInput[i].invoiceBalance;
            console.log("myInvoiceBalance "+ myInvoiceBalance);
            var myInsuredAmount = myInput[i].insuredAmount;
            console.log("myInsuredAmount "+ myInsuredAmount);
            var myPaymentDays = myInput[i].paymentDays;
            console.log("myPaymentDays "+ myPaymentDays);
            var myConfirmed = myInput[i].confirmed;
            myConfirmed = convertStringX(myConfirmed, 1);
            console.log("myConfirmed "+ myConfirmed);

            createInvoice(myVendorAddress, myInvoiceID, myInvoiceDate, myPaymentDays, myInvoiceAmount, myInsuredAmount, myAmountPaid, 
                myConfirmed, myInsurerAddress, myClientAddress, myCurrCode);
            }
        }

        // This was the missing link
        res.send("Data received!");

    });

const port = 80;

app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

The problem I am sure has to with the asynchronous nature of the call to the blockchain, but I quite new to node and HTTP requests.

Anyone got any ideas? Thanks!

0

I solved it! The answer is really simple, but maybe I can help someone else by sharing the solution.

I did not send back a receipt of the request from the client. I added the line:

res.send("Data received!");

I put it just before the end of the POST after looping through all the records received. I have also updated the code above to reflect this. Easy when you know how!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.