I am trying to call a public function of a contract to display some data to the user. I am using web3.js to create a Contract object and call() a method. Everything works on my local node but Infura complains about gas. To be clear, this code is simply running a method call in the node’s local EVM, not sending a transaction to be included in the blockchain, so I’m not sure why a gas limit is relevant. I have tried passing various gas arguments but Infura seems to cap it at 19981536.
If I run estimateGas() on the method, it returns about 39000000. Infura won’t even let estimateGas() finish so I also did that on my local Geth node.
Everything was working with Infura a week ago, so my guess is either the method call recently went over Infura’s call gas limit (due to state changes on mainnet), or Infura recently changed the call gas limit.
So, can Infura comment on whether there is a gas limit for eth_call? Is this in the docs somewhere? Does Infura+ increase it?
Hi @talkingant . Earlier this week we added a gas cap of double the block gas limit to eth_call and eth_estimateGas to prevent Denial of Service attacks. I apologize that you ran into this without it being clear in the docs. The intention with setting the limit to double the block gas limit was that it shouldn’t effect existing users since no call should take more than the block gas limit.
The reason this public function exists is to avoid hundreds of individual eth_calls. Essentially there is an array of addresses in the contract storage, and I need to iterate through this array and call a function on each address to get some info about the address. The public function was never intended to be run in a transaction. Instead, it allows one eth_call to the node and it runs that array iteration in the EVM, then returns an array of results. The alternative would be to do many eth_calls like:
eth_call for array length
Inside for loop, eth_call getArrayElement(index) then eth_call getInfo() on that address
If there are 100 elements in the array, then that is 201 eth_calls.
So I think there are many use cases where there is some unbounded array in contract storage, and to minimize HTTP/RPC requests the contract authors create a public view function that bundles the array iteration into one method call.
I understand the need to avoid DoS attacks. If eth_call is going to have a gas limit then we need a new design pattern for these public convenience functions that limit computation while still offering a way to reduce number of RPC requests to the node. I’m not sure what the solution is for the current design pattern. Perhaps you could default eth_call to 2x gaslimit, but allow the requester to specify a larger gas limit, and do more severe rate limiting for eth_calls and eth_estimateGas with custom gas limits.
For now, I humbly ask if you could raise the eth_call limit to 4x the gas limit, which should be enough for my method call at the moment.
Hi @talkingant after discussing with our team, we’re planning on upping the gas cap limit to 10x the block gas limit but because of the change required we likely won’t be able to update this until the Istanbul fork next week. We pushed the documentation change for now https://infura.io/docs/ethereum/json-rpc/eth_estimateGas to show the limit at 2x block gas limit and we will update the docs when we are able to up this to 10x next week. Are you able to workaround this issue for now? How disruptive is this to your users?
Hi Robert. We released the update in early December to set the limit to 10X. Is that still not sufficient for your purposes? We tried to set a lower limit to start but would be open to raising it if there is a good reason to. We don’t want to set it too high unnecessarily.
@mudgen, can you provide more details on what you’re executing that is hitting that gas cap? If you don’t want to discuss in public you can contact us at firstname.lastname@example.org and we can discuss over email (please mention myself and EG in the email so we are sure it is routed to us). That said, if you’re open to discussing it publicly that’s our preferred method as it helps the rest of the community learn as well.
Hi @mudgen, so I’m not very versed in smart contract development, but I think as currently implemented it’ll be very hard to make a version of winners that doesn’t consume a very large amount of gas. I suspect that even if we raised the gas cap enough for the current state to succeed, it’ll just hit the new cap again as new entrants are added.
I think in general smart contract calls need to be very limited in the data they access and should avoid iterating through state data (e.g. raffle.raffleItems and raffle.entrants). Unfortunately since I’m also not a solidity developer I don’t know where best to go for advice on making your contract more gas efficient, but I’ll ask around in the team to see if anyone has pointers on what you could do or where you could go to try to make the contract work within existing gas constraints.