Skip to content

Hardhat's console.log precompiled contract execution inconsistency #4050

Open
@michprev

Description

@michprev

Component

Anvil

Have you ensured that all of these are up to date?

  • Foundry
  • Foundryup

What version of Foundry are you on?

forge 0.2.0 (a44159a 2023-01-03T00:04:00.577535633Z)

What command(s) is the bug in?

anvil --prune-history --port 8545 --gas-price 0 --base-fee 0 --steps-tracing

Operating System

Linux

Describe the bug

From my understanding, precompiled contracts behave differently when called (CALL, CALLCODE, DELEGATECALL, STATICCALL opcodes) in a way that an execution context for the precompiled contract is not even started, and the execution continues in the caller contract.

If you consider the following function:

function callDatacopy(bytes memory data) public returns (bytes memory) {
    bytes memory ret = new bytes(data.length);
    assembly {
        let len := mload(data)
        if iszero(call(gas(), 0x04, 0, add(data, 0x20), len, add(ret,0x20), len)) {
            invalid()
        }
    }

    return ret;
}

It calls the identity (0x4) precompiled contract.

Looking at the CALL trace in debug_traceTransaction for this function call:

{'depth': 1, 'gas': 29977308, 'gasCost': 118, 'op': 'CALL', 'pc': 229, 'stack': ['0xcaa26032', '0x5f', '0x80', '0x60', '0xc0', '0x6', '0x6', '0xe0', '0x6', '0xa0', '0x0', '0x4', '0x1c96adc']}
{'depth': 1, 'gas': 29977190, 'gasCost': 3, 'op': 'PUSH2', 'pc': 230, 'stack': ['0xcaa26032', '0x5f', '0x80', '0x60', '0xc0', '0x6', '0x1']}

There is no STOP opcode (or any other opcode) with depth 2. This is consistent with other development chains (hardhat, ganache) and especially with geth.

However, for the Hardhat's console.log precompiled contract (0x000000000000000000636F6e736F6c652e6c6f67), Anvil behaves differently:

{'depth': 2, 'gas': 29468076, 'gasCost': 2600, 'op': 'STATICCALL', 'pc': 18898, 'stack': ['0x0', '0xffffffffffffffffffffffffffffffffffffffff', '0x80', '0x120', '0x63b89b50', '0x0', '0x0', '0xa513e6e4b8f2a923d98304ec87f64353c4d5c853', '0x0', '0x2a0', '0xa513e6e4b8f2a923d98304ec87f64353c4d5c853', '0x4', '0xc87b56dd00000000000000000000000000000000000000000000000000000000', '0x1621', '0x707', '0x0', '0x0', '0xe4', '0x360', '0x636f6e736f6c652e6c6f67', '0x1c1a5ac']}
{'depth': 3, 'gas': 29005078, 'gasCost': 0, 'op': 'STOP', 'pc': 0, 'stack': []}

The first trace is the call to the console.log contract. The second trace is STOP in the context of the console.log contract, which differs from the behavior for other precompiled contracts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions