[Ethereum] signing a transaction on web3js with private key and broadcasting to nodes

blockchainsolidity

I am having an issue with ethereum based project.

I made web3 API to communicate to the blockchain. I did this two ways. both call the same function on same address:

METHOD 1 (Using Unlocked accounts provided by testrpc):

This is Js code which calls the contract:

lottery.generate = function (req, res) {
    var lotteryUsers = helper.getLotteryUsers();

    var biddingTime = req.body.bidding_time; //seconds
    var pricePerEntry = web3.utils.toWei(req.body.price_in_ether, 'ether'); //ether
    var minEntries = req.body.min_entries; //min entries per lottery
    var id = req.body.id; //id of lottery

    lotteryUsers
        .methods
        .createLottery(biddingTime, pricePerEntry, minEntries, id)
        .estimateGas()
        .then(function(gasAmount) {
            lotteryUsers
                .methods
                .createLottery(biddingTime, pricePerEntry, minEntries, id)
                .send({gas: gasAmount, from: config.account}) //config.account is test account
                .then(function(receipt) {
                    console.log("receipt", receipt);
                    res.send(receipt);
                })
                .catch(function(error) {
                    console.log("error", error);
                    res.status(500).send(error.toString());
                });
        })
        .catch(function(error) {
            res.send(error);
        });
};

It works perfectly. Creates an entry on blockchain. and returns me :

{
    "transactionHash": "0x79e459c35e6125b63a3c15bf18868bb79397fc2355ac08716fa5b5609a112579",
    "transactionIndex": 0,
    "blockHash": "0x0000ce5d0ca7699c6757678833b0d1fe0b506eb55a6a99fdffd4e188c7750a55",
    "blockNumber": 9,
    "gasUsed": 589396,
    "cumulativeGasUsed": 589396,
    "contractAddress": null,
    "status": true,
    "events": {
        "NewLottery": {
            "logIndex": 0,
            "transactionIndex": 0,
            "transactionHash": "0x79e459c35e6125b63a3c15bf18868bb79397fc2355ac08716fa5b5609a112579",
            "blockHash": "0x0000ce5d0ca7699c6757678833b0d1fe0b506eb55a6a99fdffd4e188c7750a55",
            "blockNumber": 9,
            "address": "0xEb6ca4A45F9F71ce55Eb8B821188ac27D1d92Fe7",
            "type": "mined",
            "id": "log_599f5c6f",
            "returnValues": {
                "0": "0x972877c35198A8dB560371cb558fE36aceBCF753",
                "1": "0xa2eF5c45f25b3b2E9559542f499402B535d89bc8",
                "2": "1524403958",
                "3": "1524404022",
                "4": "100000",
                "5": "9",
                "6": "25",
                "7": "10",
                "owner": "0x972877c35198A8dB560371cb558fE36aceBCF753",
                "usersContractAddress": "0xa2eF5c45f25b3b2E9559542f499402B535d89bc8",
                "entryTime": "1524403958",
                "lotteryEnd": "1524404022",
                "pricePerEntry": "100000",
                "startBlock": "9",
                "id": "25",
                "minEntries": "10"
            },
            "event": "NewLottery",
            "signature": "0x637e63e954826293e14c38de613bec8b58c00ec77125234b9aa753f78626732d",
            "raw": {
                "data": "0x000000000000000000000000972877c35198a8db560371cb558fe36acebcf753000000000000000000000000a2ef5c45f25b3b2e9559542f499402b535d89bc8000000000000000000000000000000000000000000000000000000005adc8ef6000000000000000000000000000000000000000000000000000000005adc8f3600000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000000a",
                "topics": [
                    "0x637e63e954826293e14c38de613bec8b58c00ec77125234b9aa753f78626732d"
                ]
            }
        }
    }
}

Notice the gas used : "gasUsed": 589396

METHOD 2 (Using users private key to manually sign the tx):

Js code which calls the same contract instance and function:

lottery.generate = function (req, res) {
    var lotteryUsers = helper.getLotteryUsers();

    var biddingTime = req.body.bidding_time; //seconds
    var pricePerEntry = web3.utils.toWei(req.body.price_in_ether, 'ether'); //ether
    var minEntries = req.body.min_entries; //min entries per lottery
    var id = req.body.id; //id of lottery
    var privateKey = req.body.private_key; //private key of the account
    var publicKey = req.body.public_key;

    var createLottery = lotteryUsers.methods.createLottery(biddingTime, pricePerEntry, minEntries, id);
    var encodedABI = createLottery.encodeABI();

    var tx = {
        gas: 4712388,
        gasPrice: 2,
        data: encodedABI
    }

    console.log("tx "+tx);
    console.log("privateKey "+privateKey);

     var successEvent = function (receipt) {
       res.status(200).send(receipt);
     }

    var failureEvent = function (error) {
       res.status(500).send({message: errorMessage});
    }

    web3.eth.accounts.signTransaction(tx, privateKey)
     .then(signed => {
      console.log("signed "+signed.toString());
      var tran = web3.eth.sendSignedTransaction(rawTx)

        tran.on('confirmation', (confirmationNumber, receipt) => {
          console.log('confirmation: ' + confirmationNumber);
        });

        tran.on('transactionHash', hash => {
          console.log('hash');
          console.log(hash);
        });

        tran.on('receipt', receipt => {
          console.log('reciept');
          console.log(receipt);
          successEvent(receipt);
        });

        tran.on('error', error => {
            console.log(error.toString());
            failureEvent(error);
        });
   });
};

Notice how I have created an ABI. then a tx object, with sufficient
gas. Then used web3 apis to sign and broadcast the tx. Also getting
events back.

Response of the api is:

{
    "transactionHash": "0x54569155c5af3744d17031787c6a5fee4c7ea468b947d76ddc7d525c5623ca2f",
    "transactionIndex": 0,
    "blockHash": "0xbaf67b7ff8449425d3ee175cb63eb078c18e4309ace58f558d7b45766d085cda",
    "blockNumber": 10,
    "gasUsed": 54171,
    "cumulativeGasUsed": 54171,
    "contractAddress": "0x6945a93653b36aCA660F230Fd2E84a0c7b394882",
    "logs": [],
    "status": true
}

The API does not error our, but somehow it executes partially on blockchain. I say partially, because of two reasons:

1) No entry is created like being created by Method 1 on the blockchain

2) Gas used in Method 2 is 1/10th of gas used in Method 1

I need your help to figure out what is the problem with method 2.

I have spent hours debugging and narrowed it down to this much , that problem is with the way i create tx object or broadcast the object. Any help would be really appreciated, thanks in advance.

Best Answer

I figured it out, Finally! :

the tx object in Method 2 does not have a "to" address.

I think without the to address, EVM was clueless where to send the tx. I had assumed lotteryUsers object would have taken care of this (since i made abi from it), but alas! i was wrong.

So remember to put in all transaction parameters in the object you plan to send with your transactions!

var tx = {
    to: config.lottery_user_address,
    gas: 4712388,
    gasPrice: 2,
    data: encodedABI
}

Note: i tried sending with and without from, both worked. I am assuming EVM figures out the "from" address from the private key. On this one i am sure.

Related Topic