[Ethereum] Error: “invalid sender” from web3.eth.sendSignedTransaction()

ethereumjs-txgo-ethereumweb3js

I have a client running a private blockchain. It was started with the following command:

geth --datadir private-chain --mine --miner.threads 4 --http --http.addr 127.0.0.1 --http.port 8545 --http.api eth,net,web3,personal --networkid 3456 console 2> private-chain/private-chain.log

My transaction is created in the following function which is supposed to send one ether. It is part of a nodejs application I wrote to interact with the private blockchain. It uses the ethereumjs-tx package. The two account parameters are passed in as strings (which include the 0x). The accounts were created in the genesis block when I initialized the blockchain. The nonce is the number returned by web3.eth.getTransactionCount for the from_account.

function send_one_ether (from_account, nonce, private_key, to_account)
{
    var transaction_data =
    {
        "from": from_account,
        "to": to_account,
        "value": 1000000000000000000,
        "nonce": nonce
    };

    var transaction = new Transaction (transaction_data);

    var bytes = [];
    var private_key_bytes = private_key.substr (2); // remove the 0x
    for (var b = 0; b < private_key_bytes.length; b += 2)
    {
        var hex_byte = private_key_bytes.substr (b, 2);
        var int_byte = parseInt (hex_byte, 16);
        bytes.push (int_byte);
    }

    transaction.sign (Buffer.from (bytes));

    var verified = transaction.verifySignature (); // returns true
    var valid = transaction.validate (); // returns false

    var serialized_transaction = transaction.serialize ();
    web3.eth.sendSignedTransaction ("0x" + serialized_transaction.toString ("hex")).on ("receipt", console.log);
}

The private_key variable passed into the above function comes from the account's keystore file under the datadir, and it was decrypted using the following code.

var json_data = JSON.parse (fs.readFileSync (file_path));
const decrypted_account = web3.eth.accounts.decrypt (json_data, pw);

The transaction object's validate function returns false, and the error message I receive from web3.eth.sendSignedTransaction says invalid sender. Does anyone have any idea what could be wrong or how to get this to work?

Best Answer

According to this issue, private blockchains are not supported by ethereumjs-tx. You have to use ethereumjs-common. So I think the problem was that, since my call to the Transaction constructor did not include a second parameter (an object specifying a chain), it probably defaulted to mainnet. But since the accounts I am working with are all on a private blockchain, they do not exist on the mainnet. Hence, the "invalid sender" error message.

In order to send the signed transaction to my private blockchain, I did the following.

const ethereumjs_common = require ('ethereumjs-common').default;

Then I had to change the way I was creating my Transaction object. (I think the first parameter to forCustomChain might simply be ignored in this case.)

var common = ethereumjs_common.forCustomChain ('ropsten', { networkId: 1994, chainId: 1994, name: 'geth' }, 'muirGlacier');
var transaction = new Transaction (transaction_data, { "common": common });

Finally, I had to add some gas to my transaction_data object.

var transaction_data =
{
    "from": from_account,
    "to": to_account,
    "value": 1000000000000000000,
    "gas": 60000,
    "nonce": nonce
};

After that, I got the receipt I was hoping to get.

Related Topic