I've used web3py to deploy a contract and send some transactions to it.

I calculate the nonce this way: nonce = web3.eth.getTransactionCount(account, "pending")

When I deploy the contract, everything goes right. Then I make a simple transaction (using the method buildTransaction), such as updating the value of a contract, and then I wait for the tx receipt. When I see it on etherscan, the transaction has been a success. But if I try to call the constant function that returns that value, I get 0, even if I had updated it with other value.

In addition, if I later try again doing that transaction, the nonce does not update, and I get the message of "nonce too low".

Can you help me with this issue? Idk what happens.

  • Which node are you connected to? It's possible that your node is a bit behind while syncing, so although it can broadcast transactions, it doesn't realize they have been mined since it hasn't seen those blocks yet. – Raghav Sood Aug 3 at 1:45
  • I am using infura. The thing is that when I try with rinkeby everything goes OK but when I change to the mainnet it fails – RJ-mac Aug 3 at 6:59
  • You were right @RaghavSood! It seems it was a bit behind. After waiting for the receipt, I've put a time.sleep(40) and it gets the right result. Any better ideas to fix it? Or any thoughts on why infura with the mainnet has this issue? – RJ-mac Aug 3 at 9:14

Not all clients support pending block well. Infura will especially have a hard time tracking your transactions while pending.

Since you are generating the transactions sequentially, a reasonable option is to increment the nonce yourself, since you know the order you want them to complete. Something like:

from web3.auto import w3

start_nonce = w3.eth.getTransactionCount(account)

txn = my_contract.functions.doThing().buildTransaction({
  'nonce': start_nonce,
})

# ... sign and send transaction ...

# Note that you do *not* have wait for the previous transaction to be mined,
# the nonce will enforce order:
txn2 = my_contract.functions.doAnotherThing().buildTransaction({
  'nonce': start_nonce + 1,
})

# ... sign and send transaction ...

receipt = w3.eth.waitForTransactionReceipt(<hash of txn2>)

# now a call to read data will include the result of running "doOtherThing"

There is a caveat: you might have a race condition where one server in Infura has the mined transaction and receipt, and another server does not. So you might get the receipt on one, and then the next request hits a different server that's a little behind. You could use the block hash in the receipt when making the call, in order to verify that the Infura node you talk to during the call is current:

my_contract.functions.getInfo().call(block_identifier=receipt.blockHash)

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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