eth-infinitism / bundler

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`BUFFER_OVERRUN` while simulating validation

pilagod opened this issue · comments

Hi there,

I was testing my custom paymaster with bundler in order to make it compatible with EIP-4337 spec. I found that when the context data (returning from _validatePaymasterUserOp) encodes more than one field, the bundler would encounter BUFFER_OVERRUN error.

Here is the minimum paymaster to reproduce this problem:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import { BasePaymaster } from "@account-abstraction/contracts/core/BasePaymaster.sol";
import { IEntryPoint } from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import { UserOperation } from "@account-abstraction/contracts/interfaces/UserOperation.sol";

contract Paymaster is BasePaymaster {
    constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) {}

    function _validatePaymasterUserOp(
        UserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 maxCost
    ) internal override returns (bytes memory context, uint256 validationData) {
        (userOp, userOpHash, maxCost);

        // This is ok
        // context = abi.encode(userOp.sender);

        // This causes the error
        context = abi.encode(userOp.sender, userOp.nonce);
    }

    function _postOp(
        PostOpMode mode,
        bytes calldata context,
        uint256 actualGasCost
    ) internal override {
        (mode, context, actualGasCost);
    }
}

And this paymaster will cause error in bundler side (in safe mode) when simulating validation:

failed:  eth_sendUserOperation error: {"message":"data out-of-bounds (length=79, offset=96, code=BUFFER_OVERRUN, version=abi/
5.7.0)","code":"BUFFER_OVERRUN"}

After investigating, I found the problem is due to this line:

const data = toHex(log.memory.slice(ofs, ofs + len)).slice(0, 1000)

The slicing restricts data in the trace step to 1000 in length at most. When paymaster encodes multiple data into the context, it would cause the revert data (revert ValidationResult(...)) length exceed 1000, and bundler would accidentally trim the data to fit that size, finally causing BUFFER_OVERRUN error when parsing the validation result at this line:

const {
name: errorName,
args: errorArgs
} = this.entryPoint.interface.parseError(data)

After I removed the data slicing in my local bundler, it did fix the problem. I'm wondering if there is any reason to restrict the data length in the trace step? Thanks.

There is no specific reason for slicing at this specific length..
We wanted to avoid returning too much data from the tracer (e.g. when returning a contract code), and 1000 seemed to be large enough.
Apparently it is too small if there is a paymaster context)