ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.29k stars 5.77k forks source link

feat: Blackbox code from compiler #12951

Closed brockelmore closed 1 year ago

brockelmore commented 2 years ago

Abstract

As the compiler gets smarter at inlining, const evaling, and keeping variables around (with stack-to-deep avoidance and the like), there is a growing need to hide/blackbox chunks of code from the compiler for testing and profiling reasons.

Motivation

I am extremely encouraged that I need to make this request. Effectively, the optimizer (especially with viaIR) is getting so smart there is a growing need to be able to tell the compiler "dont touch this". For example: https://github.com/foundry-rs/foundry/issues/1373

Foundry allows users to change global variables like block parameters in a test. The issue is the optimizer now is smart enough that later usage of block.timestamp is compiled away after the first usage and duped, because in normal circumstances, this is constant throughout a transaction. There have also been times when trying to gas profile a library that under viaIR, it gets const evaled (in these tests for example: https://github.com/recmo/experiment-solexp/blob/main/src/test/FixedPointMathLib.t.sol).

Specification

Blackboxing would take an expression/code block and not perform any constant evaluation on it or perform optimizations on its output.

One option is to add a blackbox code block similar to unchecked or assembly blocks:


function t() public returns (uint256 a) {
    blackbox { a = 5 + 5; }
}

The above would never evaluate the function at compile time and would always effectively generate:

PUSH1(0x05)
PUSH1(0x05)
ADD
PUSH1(0x00)
MSTORE
PUSH1(0x00)
PUSH1(0x20)
RETURN

Or whatever. I am not entirely sure of optimizations that occur on raw bytecode, but if peephole optimizations may still take place on it, one way you might avoid that is basically just trick the peephole optimizer into thinking its a sort of link reference (i.e. _$blackboxRef1$_)? Then as the last step, fill in any references with the associated blackbox opcodes.

Backwards Compatibility

Would add a new keyword blackbox

cameel commented 2 years ago

This seems related to this earlier issue from @cgewecke and @Ferparishuertas: #10354. That issue is about something else (getting "stack too deep" with optimizer disabled) but the underlying use case is very similar - needing to insert some "instrumentation" code that should go through the optimizer unmodified - for the purpose of tracking coverage in that specific case.

@brockelmore Do you need to be able to do this at Solidity level or would compiling first to Yul, then inserting your snippet and finally assembling to bytecode be enough? If it's the latter then I guess verbatim could be used as a workaround since the compiler won't optimize verbatim blocks.

I am not entirely sure of optimizations that occur on raw bytecode, but if peephole optimizations may still take place on it,

Yeah, there's another optimization pass on EVM assembly after Yul optimizer finishes. It's basically the same optimizer that's used in the legacy non-Yul pipeline. We have fine-grained settings for selecting optimizations done at this stage. You can disable the peephole optimizer by setting settings.optimizer.details.peephole to false in Standard JSON. Also note that you have to explicitly disable it - it still runs if you just set settings.optimizer.enabled to false (at least on 0.8.6+, there was a bug related to that earlier, see Input description for details).

axic commented 2 years ago

I think this function is really about verbatim, given the goal of blackbox would be the code remains untouched. One just needs to finish #12067.

@brockelmore can this be closed or do you think blackbox would be useful beyond small snippets accomplishable via verbatim?

github-actions[bot] commented 1 year ago

This issue has been marked as stale due to inactivity for the last 90 days. It will be automatically closed in 7 days.

github-actions[bot] commented 1 year ago

Hi everyone! This issue has been automatically closed due to inactivity. If you think this issue is still relevant in the latest Solidity version and you have something to contribute, feel free to reopen. However, unless the issue is a concrete proposal that can be implemented, we recommend starting a language discussion on the forum instead.