Web3.py – How to Get Gas Estimate and Gas Price on Polygon Mumbai Chain Using Web3.py

gas-estimategas-pricepolygonweb3.py

I have deployed a contract on Goerli test net and used the following to get the estimated gas and current gas price.

contract = web3.eth.contract(address=contract_address, abi=contract_abi)    

contract_transaction_struct = contract.functions.addRow(_var1, _var2,...).buildTransaction()

gas_estimate = web3.eth.estimateGas(contract_transaction_struct)

current_gas_price = web3.eth.gasPrice

and it worked fine.

Now, I deployed the same contract on Polygom Mumbai test net.

Getting the following error

contract_transaction_struct = contract.functions.addRow(_root, _length, _secret, _file_extension, _storage_peers, _backup_peers, _upload_endpoint ).buildTransaction()   File "/usr/local/lib/python3.6/site-packages/web3/_utils/decorators.py",

line 51, in wrapper
return to_wrap(*args, **kwargs) File "/usr/local/lib/python3.6/site-packages/web3/contract.py", line 1112,
in buildTransaction
return self.build_transaction(transaction) File "/usr/local/lib/python3.6/site-packages/web3/contract.py", line 1107,
in build_transaction
**self.kwargs File "/usr/local/lib/python3.6/site-packages/web3/contract.py", line 1672,
in build_transaction_for_function
prepared_transaction = fill_transaction_defaults(web3, prepared_transaction) File "cytoolz/functoolz.pyx", line 249, in
cytoolz.functoolz.curry.call File
"/usr/local/lib/python3.6/site-packages/web3/_utils/transactions.py",
line 114, in fill_transaction_defaults
default_val = default_getter(web3, transaction) File "/usr/local/lib/python3.6/site-packages/web3/_utils/transactions.py",
line 64, in
web3.eth.max_priority_fee + (2 * web3.eth.get_block('latest')['baseFeePerGas']) File
"/usr/local/lib/python3.6/site-packages/web3/eth.py", line 690, in
get_block
return self._get_block(block_identifier, full_transactions) File "/usr/local/lib/python3.6/site-packages/web3/module.py", line 60, in
caller
null_result_formatters) File "/usr/local/lib/python3.6/site-packages/web3/manager.py", line 197, in
request_blocking
response = self._make_request(method, params) File "/usr/local/lib/python3.6/site-packages/web3/manager.py", line 150, in
_make_request
return request_func(method, params) File "/usr/local/lib/python3.6/site-packages/web3/middleware/formatting.py",
line 94, in middleware
response = make_request(method, params) File "/usr/local/lib/python3.6/site-packages/web3/middleware/gas_price_strategy.py",
line 90, in middleware
return make_request(method, params) File "/usr/local/lib/python3.6/site-packages/web3/middleware/formatting.py",
line 94, in middleware
response = make_request(method, params) File "/usr/local/lib/python3.6/site-packages/web3/middleware/attrdict.py",
line 33, in middleware
response = make_request(method, params) File "/usr/local/lib/python3.6/site-packages/web3/middleware/formatting.py",
line 94, in middleware
response = make_request(method, params) File "/usr/local/lib/python3.6/site-packages/web3/middleware/formatting.py",
line 96, in middleware
return _apply_response_formatters(method=method, response=response, **formatters) File
"/usr/local/lib/python3.6/site-packages/web3/middleware/formatting.py",
line 51, in _apply_response_formatters
return _format_response("result", result_formatters[method]) File
"/usr/local/lib/python3.6/site-packages/web3/middleware/formatting.py",
line 47, in _format_response
response, response_type, method_response_formatter(appropriate_response) File
"cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.call
File
"/usr/local/lib/python3.6/site-packages/eth_utils/applicators.py",
line 72, in apply_formatter_if
return formatter(value) File "cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.call File
"/usr/local/lib/python3.6/site-packages/eth_utils/functional.py", line
45, in inner
return callback(fn(*args, **kwargs)) File "/usr/local/lib/python3.6/site-packages/eth_utils/applicators.py",
line 84, in apply_formatters_to_dict
yield key, formatterskey File "/usr/local/lib/python3.6/site-packages/web3/middleware/validation.py",
line 79, in _check_extradata_length
len(result), MAX_EXTRADATA_LENGTH, result web3.exceptions.ExtraDataLengthError: The field extraData is 97 bytes,
but should be 32. It is quite likely that you are connected to a POA
chain. Refer to
http://web3py.readthedocs.io/en/stable/middleware.html#geth-style-proof-of-authority
for more details. The full extraData is:
HexBytes('0xd682030283626f7288676f312e31392e34856c696e7578000000000000000000ed945a3cb9bde3dd4c588e8710adb72e1668e8933f5c6d840d37e615658cbd741944e15deda7e4905984ae8c041574eee5b2daf32b7166c9457c6a71525a705b00')

I did some research and added

w3.middleware_stack.inject(geth_poa_middleware, layer=0)

Got error

w3.middleware_stack.inject(geth_poa_middleware, layer=0) AttributeError: 'Web3' object has no attribute 'middleware_stack'

I am using Web3.py version 5.31.3.

Anyways, I again chaged to

w3.add_middleware(geth_poa_middleware)

Getting the same error.

Any suggestions?

Edit: As suggested by Mikko Ohtamaa..yes was doing it wrong. the correct way to use geth_poa_middleware is

web3.middleware_onion.inject(geth_poa_middleware, layer=0)

As suggested here

Best Answer

This is because the default web3.py APIs need a special support for some blockchains, as they insert extra data in their transactions.

Your suggestion how to solve the problem is correct and should work. If it does not work then you are doing it incorrectly and you need to debug your code e.g. using Python debuggers to figure out why this middleware is not being activated for your application.