2

I have a function that is being called by multiple users (say 3). That value is set by owner earlier as a constant. Inside this function there's a check whether it's the last user (3) or not. If yes then another function executes. It means that the last user pays more gas (figured it out suddenly). So, if the transaction of the second user has not been completed yet and the third user starts a transaction, he pays the same amount of gas as the second user because contract still doesn't know if it's the last transaction (user). Let's say the second transaction has been completed while the third is executing. And the error occurs because the third user became the last one and needed more gas to pay now. Maybe is there any way to avoid that behavior? Example of that function:

function pay() payable external {
    cur += 1;
    require(cur <= max);
    players[msg.sender] = true;
    playerKeys.push(msg.sender);
    if (cur == max){
        anotherFunction();
    }
}
0

ORIGINAL ANSWER

Wallets calculate the gas limit to use by calling a node with the eth_estimateGas RPC method. This call works by performing a dry-run of the transaction based on the current state of the blockchain, and seeing how much gas is consumed.

What you are asking to do amounts to "Can a gas estimation be performed that takes into consideration existing pending transactions?" While technically this could be possible, it would require a node first simulating every other pending transaction with a given gas price > that of the transaction it wishes to estimate. Even then, the node could not say with certainty that the next block will be mined with exactly the same sequence of transactions. The miner's local pending transaction pool might look different from the node's, other transactions might be broadcasted after the simulation that have a higher gas price, or the miner and node might use different logic when deciding how to sequence the transactions.

In short - the extra computation required, lack of certainty of results, and infrequency where this situation matters are all reasons that I don't think anyone has attempted to implement something like this before.

A far simpler approach is to tell your users to set the gas limit manually, and give them a value that will still be enough if they are the last user.

EDIT BASED ON COMMENTS

Is it possible to reconstruct the logic to not charge extra gas from the last user for extra function in condition? I need to execute that function if limit of payments has reached.

It's a hacky approach that might make an auditor groan, but you could create a storage array that you write garbage data to in all but the final transaction, then delete this data in the final tx. Writing to storage is very expensive, and deleting gives a gas refund. With some tests you could find a balance where you increase the gas costs from the initial calls and reduce the final one such that they roughly even out.

In the following example I have added comments that hopefully make the concept more clear:

bytes32[] garbage;

function pay() payable external {
    cur += 1;
    require(cur <= max);
    players[msg.sender] = true;
    playerKeys.push(msg.sender);
    if (cur == max){
        // setting the array length to 0 deletes all values within it
        // this gives a 15000 gas refund per entry
        garbage.length = 0;
        anotherFunction();
    } else {
        garbage.push(0x01); // adding a value to a dynamic array costs ~25000 gas
    }
}
  • Thank you for the explanation. Can I ask one another question? Is it possible to reconstruct the logic to not charge extra gas from the last user for extra function in condition? I need to execute that function if limit of payments has reached. I'm not sure I'm doing right. Thanks in advance – Denis Lolik Sep 6 at 9:41
  • It's a hacky approach that might make an auditor groan, but you could create a storage array that you write garbage data to in all but the final transaction, then delete this data in the final tx. Writing to storage is very expensive, and deleting gives a gas refund. With some tests you could find a balance where you increase the gas costs from the initial calls and reduce the final one such that they roughly even out. – iamdefinitelyahuman Sep 6 at 9:49
  • Could you give an example? I don't think I got you right – Denis Lolik Sep 6 at 9:56
  • see the edit to my answer – iamdefinitelyahuman Sep 6 at 10:45
  • Thank you! I'll try it out and respond back – Denis Lolik Sep 6 at 10:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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