Web3.py – Signing a Raw Transaction on Contract Function

web3.py

I'm having some trouble signing a transaction on a contract function. First I build the transaction:

transaction = contract_instance.functions.buy().buildTransaction(
            {
                'nonce': w3.eth.getTransactionCount(w3.eth.accounts[1]) + 1,
                'from': w3.eth.accounts[1],
                'gas': 70000000,
                'gasPrice': 18000000000,
                'value': _value,
                'chainId': 10
            }
        )

Then I decrypt:

key = decrypt_account(address=w3.eth.accounts[1], passphrase='This')

then I sign:

signed = w3.eth.account.signTransaction(transaction, key)

then I send:

w3.eth.sendRawTransaction(signed.rawTransaction)

The problem comes when the function in the contract is called: buy()

function buy() isRunning validAddress payable public {
    uint256 amount = msg.value;
    amount = amount.div(buyPrice);
    amount = amount.mul(10**18);
    _transfer(this, msg.sender, amount);
    Buy(this, msg.sender, amount, buyPrice);
}

The tx_hash response I get is:

AttributeDict({'to': '0x6d3921d65b2127bF42035CF6E39B9c77d44443Eb', 'gasPrice': 21000000000, 'value': 1000000000000000000, 'hash': HexBytes('0xfc6ad0477afd00a5d9b44917db4e42e88437edee6902c0c963061d4453a51d89'), 's': HexBytes('0x7295aa1a2322d96e12ee05464b4502764873ea6167c87ac9641ee358335538cd'), 'from': '0xcE4f50A654c8cd561207725f8F0BF5801c2c9613', 'blockHash': HexBytes('0x0000000000000000000000000000000000000000000000000000000000000000'), 'r': HexBytes('0xf7040b0bf0cc13c6f469cc623603422031cdc7f1a1c2119f6e0844d12aafcd3c'), 'blockNumber': None, 'transactionIndex': 0, 'nonce': 3, 'gas': 6000000000, 'v': 56, 'input': '0xa6f2ae3a'})

As we can see the block hash looks empty and the blockNumber is None. Thats normally what I get when there was an error.

Now if I dont use the sign method and I just unlock the account:

I get a tx_hash response of:

AttributeDict({'hash': HexBytes('0xfef1bda5fc01e0ee937507cd79f911fc8c96b9819708ce114f353d8ea3ad2495'), 'input': '0xa6f2ae3a', 'gasPrice': 18000000000, 'from': '0xcE4f50A654c8cd561207725f8F0BF5801c2c9613', 'to': '0x6d3921d65b2127bF42035CF6E39B9c77d44443Eb', 'v': 27, 'gas': 700000, 'value': 1000000000000000000, 'nonce': 1, 'transactionIndex': 0, 'r': HexBytes('0x725fa7d26c3abf3e99c684bff8ec45133983635c1440d833ed66728aa67a037d'), 'blockNumber': 40, 's': HexBytes('0x720a5bcad1b8d71cf60031e838aedd32dc2b9b82d40cd52ab682a168ff50fdfa'), 'blockHash': HexBytes('0xa2292df37f6d7348c5cd6057f672a6b7235539f47b68ea0af7ed70f39dca71b9')})

So its without a doubt something with the signing and sending of the transaction.

Just so you can see how I call the transaction if I unlock:

contract_instance.functions.buy().transact({'from': user, 'gas': 700000, 'value': _value})

I'm really stuck on this one. Also, I'm running a test network chain if that matters.

{
"parentHash":  "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0xf2419003e9058198c71e42bb35f94b4452fadfa8",
"extraData": "0x686f727365",
"config": {
  "daoForkBlock": 0,
  "daoForSupport": true,
  "homesteadBlock": 0
},
"timestamp": "0x0",
"mixhash":  "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0xdeadbeefdeadbeef",
"alloc": {
  "0x3d48e3a6a661e5dc56db193e49d484e79c927652": {
    "balance": "1000000000000000000000000000000"
  }
},
"gasLimit": "0x3b62df92707000",
"difficulty": "0x01"
}

Best Answer

The problem is that the transaction sets a chainId of 10, but the genesis file does not specify chainId.

A mismatched chainId will cause a failure in your node (which is supposed to happen, that's how the node prevents transaction replays).


If your node does not support chainId in the genesis file (which populus may not), then setting chainId to None in the transaction is the correct solution.

However, if you are using geth, you can set the chainId in the genesis file, like so:

{
"parentHash":  "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0xf2419003e9058198c71e42bb35f94b4452fadfa8",
"extraData": "0x686f727365",
"config": {
  "chainId": 10,
  "daoForkBlock": 0,
  "daoForSupport": true,
  "homesteadBlock": 0
},
"timestamp": "0x0",
"mixhash":  "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0xdeadbeefdeadbeef",
"alloc": {
  "0x3d48e3a6a661e5dc56db193e49d484e79c927652": {
    "balance": "1000000000000000000000000000000"
  }
},
"gasLimit": "0x3b62df92707000",
"difficulty": "0x01"
}