Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investigate gas estimation with large amounts of gas #1997

Open
dcroote opened this issue May 12, 2024 · 6 comments
Open

Investigate gas estimation with large amounts of gas #1997

dcroote opened this issue May 12, 2024 · 6 comments
Assignees

Comments

@dcroote
Copy link
Contributor

dcroote commented May 12, 2024

A user on Discord is reporting gas estimation issues when fulfillment uses a large amount of gas:

for this kind of behavior, you must keep the gas of the fulfillment less than 1.6M. the problem is that; when the estimated gas increases, the estimation gets a little less than what the transaction uses.

I don't think it's you guys problem because i've checked the airnode code and you guys are doing the estimation like everybody else does, but you can just start out by creating an fulfillment that has like 2M gas

@dcroote dcroote self-assigned this May 12, 2024
@bbenligiray
Copy link
Member

As a note, the user reporting this seems to be using base-sepolia-testnet

https://sepolia.basescan.org/tx/0xff1400c4eb0fbcede0b01a456060f3702b0ae4504268d29fdcf44a8359671029#eventlog

@tarik0
Copy link

tarik0 commented May 13, 2024

As a note, the user reporting this seems to be using base-sepolia-testnet

https://sepolia.basescan.org/tx/0xff1400c4eb0fbcede0b01a456060f3702b0ae4504268d29fdcf44a8359671029#eventlog

The problem does not only happen in Base Sepolia, It also happens in Ethereum Sepolia as well.

@tarik0
Copy link

tarik0 commented May 13, 2024

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@api3/airnode-protocol/contracts/rrp/interfaces/IAirnodeRrpV0.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MockedRequester is
    Ownable
{
    address internal _airnodeRrp;
    address internal _airnode;
    address internal _sponsorWallet;
    bytes32 internal _endpointIdUint256;

    event Requested(bytes32 requestId);

    constructor() {}

    function setSettings(
        address airnodeRrp,
        address airnode,
        address sponsorWallet,
        bytes32 endpointIdUint256
    ) external onlyOwner {
        _airnodeRrp = airnodeRrp;
        _airnode = airnode;
        _sponsorWallet = sponsorWallet;
        _endpointIdUint256 = endpointIdUint256;

        IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);
    }

    struct Request {
        uint256 fromId;
        uint256 toId;
        uint256 timestamp;
        bool hasReferral;
    }

    struct Response {
        uint256 rawSeed;
        uint256 timestamp;
        bool hasReferral;
    }

    function requestUint256(uint256 tokenIdCount) external onlyOwner {
        bytes32 requestId = IAirnodeRrpV0(
            _airnodeRrp
        ).makeFullRequest(
            _airnode,
            _endpointIdUint256,
            address(this),
            _sponsorWallet,
            address(this),
            this.fulfillUint256.selector,
            ""
        );

        _expectedRequests[requestId] = Request(0, tokenIdCount, block.timestamp, false);

        emit Requested(requestId);
    }

    mapping(bytes32 => Request) private _expectedRequests;
    mapping(bytes32 => Response) private _requestToResponse;
    uint256 private _totalProbability;

    function fulfillUint256(bytes32 requestId, bytes calldata data) external {
        // validate request
        Request memory seedRequest = _expectedRequests[requestId];
        if (msg.sender != _airnodeRrp) {
            revert();
        }

        // decode seed
        uint256 rawSeed = abi.decode(data, (uint256));

        // set request's response
        _requestToResponse[requestId] = Response(rawSeed, seedRequest.timestamp, seedRequest.hasReferral);

        // iterate over token ids
        for (uint256 i = seedRequest.fromId; i < seedRequest.toId; i++) {
           _totalProbability += (rawSeed ^ i) % type(uint32).max;
        }
        delete _expectedRequests[requestId];
    }
}

You can use this contract to test out the fulfillment as I did. This is the mocked version of how my actual fulfillment is happening.

@dcroote
Copy link
Contributor Author

dcroote commented May 20, 2024

@tarik0 - what sorts of values are representative for your tokenIdCount?

@dcroote
Copy link
Contributor Author

dcroote commented May 21, 2024

@bbenligiray / @Siegrift - I spun up a local Airnode and local hardhat network, deployed the contract (with a few slight variations), and tested increasingly large tokenIdCount values, which are critical to the gas consumption as this value dictates the loop iteration count in the fulfillment function (seedRequest.toId). Gas estimation was fine for values of 500 and 1000 as shown by the following Airnode DEBUG log snippets, respectively:

INFO Gas limit is set to 554767 (AirnodeRrp: 41995 + Fulfillment Call: 512772)
INFO Gas limit is set to 955425 (AirnodeRrp: 42019 + Fulfillment Call: 913406)

However, when I tried 2000, it failed due to a timeout, and the source of the error was here:

const operation = (): Promise<ethers.BigNumber> => voidSignerAirnodeRrp.estimateGas(goTx.data);
const goRes = await go(operation, { retries: 1, attemptTimeoutMs: BLOCKCHAIN_CALL_ATTEMPT_TIMEOUT });
if (!goRes.success) {
const errorLog = logger.pend(
'ERROR',
`Fulfillment call overhead estimation failed for Request:${request.id} with ${goRes.error}`,
goRes.error
);
return [[noticeLog, errorLog], goRes.error, null];

indicating that there is a timeout occurring when trying to estimate the fulfillment call overhead. Full logs here:

2024-05-21 00:10:14 [2024-05-21 07:10:14.791] DEBUG Attempting to estimate required gas to fulfill API call for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84... Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] DEBUG Attempting to estimate AirnodeRrp overhead to fulfill API call for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84... Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] DEBUG Attempting to estimate fulfillment call overhead to fulfill API call for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84... Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] ERROR Fulfillment call overhead estimation failed for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84 with Error: Operation timed out Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] ERROR Error: Operation timed out
2024-05-21 00:10:14     at createGoError (/usr/local/share/.config/yarn/global/node_modules/@api3/promise-utils/build/cjs/index.js:49:30)
2024-05-21 00:10:14     at /usr/local/share/.config/yarn/global/node_modules/@api3/promise-utils/build/cjs/index.js:112:16
2024-05-21 00:10:14     at Generator.throw (<anonymous>)
2024-05-21 00:10:14     at rejected (/usr/local/share/.config/yarn/global/node_modules/@api3/promise-utils/build/cjs/index.js:6:65) Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] DEBUG Attempting to fulfill API call for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84... Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] INFO Submitting API call fail for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84... Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
2024-05-21 00:10:14 [2024-05-21 07:10:14.791] INFO Transaction:0x6a0a56b5188c4b62e7af3ff6b594886e8f38da44cadd3a6f0050588337fc43ae submitted for Request:0xe26cb0ec67ecbbd1fad28023b6e8715e7725c7f7561abfc8fcac94921e1a1f84 Coordinator-ID:161e98b7836ea821, Chain-ID:31337, Provider:exampleProvider, Endpoint-ID:0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4, Sponsor-Address:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266

@Siegrift Siegrift assigned bbenligiray and unassigned dcroote Jun 4, 2024
@tarik0
Copy link

tarik0 commented Jun 4, 2024

@dcroote The amounts you've entered are almost the same as mine. I also had problems with more than 500 token IDs.

I bet the simulation gets timed out since the transaction flow gets bigger but I don't know why this suggests a gas limit instead of throwing some error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants