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

deployedBytecode output is empty in Yul mode for contracts with bytecode dependencies #15745

Open
cameel opened this issue Jan 20, 2025 · 0 comments
Labels
bug 🐛 low effort There is not much implementation work to be done. The task is very easy or tiny. low impact Changes are not very noticeable or potential benefits are limited. must have eventually Something we consider essential but not enough to prevent us from releasing Solidity 1.0 without it.

Comments

@cameel
Copy link
Member

cameel commented Jan 20, 2025

Description

The evm.deployedBytecode output in Standard JSON is available both for Yul and Solidity, but works reliably only for Solidity. In Yul a heuristic is used to find the runtime object and the presence of more than one nested object is enough to confuse it. The result is that for contracts with bytecode dependencies the output is empty. This makes the result of two-stage compilation via Yul different than single-step compilation.

The heuristic is inconsistent with Specification of Yul Object, which documents the _deployed suffix as the factor determining the runtime object.

The problem exists only in the Standard JSON interface because CLI does not provide outputs for the deployed bytecode.

Environment

  • Compiler version: 0.8.28
  • Compilation pipeline: Yul via IR

Steps to Reproduce

Single-step compilation

step1.json

{
    "language": "Solidity",
    "sources": {
        "input.sol": {"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity *; contract C {} contract D { bytes b = type(C).creationCode; }"}
    },
    "settings": {
        "outputSelection": {"*": {"*": ["evm.deployedBytecode", "ir"]}}
    }
}
solc --standard-json step1.json | jq '.contracts."input.sol".D.evm.deployedBytecode' --indent 4 
{
    "functionDebugData": {},
    "generatedSources": [],
    "immutableReferences": {},
    "linkReferences": {},
    "object": "60806040525f5ffdfea2646970667358221220441547fad1e807dbbd779e12ccb81af8fce9f606e7c163311e37379dcbba1c5364736f6c634300081c0033",
    "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 PUSH0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PREVRANDAO ISZERO SELFBALANCE STATICCALL 0xD1 0xE8 SMOD 0xDB 0xBD PUSH24 0x9E12CCB81AF8FCE9F606E7C163311E37379DCBBA1C536473 PUSH16 0x6C634300081C00330000000000000000 ",
    "sourceMap": "69:46:0:-:0;;;;;"
}

Deployed bytecode is present as expected. The compiler selects the right nested object for D because it relies on the _deployed suffix:

std::string deployedName = IRNames::deployedObject(_contract);
solAssert(!deployedName.empty(), "");
tie(compiledContract.evmAssembly, compiledContract.evmRuntimeAssembly) = stack.assembleEVMWithDeployed(deployedName);

Two-step compilation

step2.json

{
    "language": "Yul",
    "sources": {
        "D.yul": {"urls": ["D.yul"]}
    },
    "settings": {
        "outputSelection": {"*": {"*": ["*"]}}
    }
}
solc --standard-json step1.json | jq --raw-output '.contracts."input.sol".D.ir' > D.yul
solc --standard-json step2.json | jq --raw-output '.contracts."D.yul".[].evm.deployedBytecode' --indent 4
null

Deployed bytecode is missing even though we're compiling the same exact contract, just in two steps. This is because in Yul mode the name of the nested object is not given and we fall back to the simplistic heuristic:

std::tie(object, deployedObject) = stack.assembleWithDeployed();

@cameel cameel added bug 🐛 low effort There is not much implementation work to be done. The task is very easy or tiny. low impact Changes are not very noticeable or potential benefits are limited. must have eventually Something we consider essential but not enough to prevent us from releasing Solidity 1.0 without it. labels Jan 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 low effort There is not much implementation work to be done. The task is very easy or tiny. low impact Changes are not very noticeable or potential benefits are limited. must have eventually Something we consider essential but not enough to prevent us from releasing Solidity 1.0 without it.
Projects
None yet
Development

No branches or pull requests

1 participant