3
function getPosts(address[] subscriptions, uint[] subscriptionIndexes, uint count) public view returns 
            (address[], bytes32[], bytes32[], uint[]) {

            address[] storage postSenders;
            bytes32[] storage postLinks;
            bytes32[] storage postComments;
            uint[] storage postTimestamps;

            while(postSenders.length < count) {
                (uint postId, address subscription) = getNextPost(subscriptions, subscriptionIndexes);


                postSenders.push(subscription);
                postLinks.push(addressToLinks[subscription][postId]);
                postComments.push(addressToComments[subscription][postId]);
                postTimestamps.push(addressToTimestamps[subscription][postId]);
            }

            return (postSenders, postLinks, postComments, subscriptionIndexes);
        }

The above works fine when I pass an array of length 311, but returns this error when I pass an array of length 312 or greater:

Returned error: base fee exceeds gas limit at Object.ErrorResponse 

I didn't realize gas was involved when just reading from the blockchain?

I've tried to increase the gas limit like this (using web3. v 1.0):

let results = await myContract.methods.getPosts(subscriptions, indexes, 3).call({gas: 1000000000});

But now I get that error every time regardless of what I put for the gas amount and regardless of how large subscriptions array is.

Any ideas on how I can make this more efficient or why its failing?

Thanks!

1 Answer 1

3

Multiple issues.

You're confusing the gas supplied with the transaction with the gasLimit. The gasLimit is a network property. On a private chain or simulator you can set the limit where you want but on a public network it's voted on by the miners and you can't control it.

The gas is the amount of fuel supplied to execute the transaction. Since no block can contain more gas than the gasLimit, no single transaction can exceed the block gasLimit. Exceeding this limit is an automatic fail.

The function is constructed in an inefficient way. By returning all of these unbounded arrays, there is no upper limit to the gas cost. In practice, this pattern is unnecessary. It's better to let clients request what they need, one element at a time. In this way, a large effort that is over-budget can be sub-divided into many smaller efforts that are individually within the budget.

While it is true that read-only operations will result in the "return" of the gas supplied (actually, since the network is not informed there is nothing to recall), gas accounting is still in play, even in the case that the function is called with "dry-run" .call() method. It will even fail if it runs out of gas.

The function itself appears to want to update storage but it uses the view modifier. That looks suspicious.

The unbounded while loop may appear to work up to a certain scale, but it will cost more and eventually fail completely.

Consider,

function getAddressPost(address poster, uint row) public view returns(...

and return a single record without any dynamic elements so the cost is equal at all scales.

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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