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

solc 0.7.1 - inconsistent bytecode created for identical contract input using standard-json compiler input #11375

Closed
nventuro opened this issue May 10, 2021 · 3 comments
Assignees
Labels
bug 🐛 codegen error Compiler generates invalid code. Critical. waiting for more input Issues waiting for more input by the reporter

Comments

@nventuro
Copy link
Contributor

This is essentially the same as #9573 - I'm opening a new issue as that one is closed, and the underlying problem already identified. This issue is about this behavior persisting in solc 0.7.1 (as per @chriseth's request here).

I was planning on distributing contract source code for third party developers to compile locally when building integrations with our system, potentially adding logs, etc. to help debug. However, despite the compilation settings being the exact same (other than the files having different names due to the package name prefix), I observed the compilation output was different.

Critically, as the original source code results in bytecode extremely close to the 24kB limit, this issue causes the compilation output to exceed this limit, making the end result non-deployable (at least not without overriding the code size limit). Typically, slight differences in bytecode, while undesirable, would be mostly not harmful, but this interaction with the 24kB limit causes severe problems.

Attached I included the compilation input, from the Hardhat-based compilation process. original is the original compilation, and library the one where the original artifacts are imported as a library.

original.txt
library.txt

@cameel cameel added bug 🐛 codegen error Compiler generates invalid code. Critical. labels May 11, 2021
@cameel cameel self-assigned this Jun 24, 2021
@cameel
Copy link
Member

cameel commented Jun 24, 2021

@nventuro I tried to reproduce this and the only differences I found are due to paths in metadata. Note that one of the contracts is using new to deploy an instance of another contract and this means it has the bytecode of that other contract (including metadata) embedded in its own code. Due to this bytecode differs not only at the very end but also somewhere in the middle where the embedded code ends.

Is that the difference you were seeing? I could not reproduce the different behavior regarding the code size limit warning (neither original.txt nor library.txt produces it on 0.7.1) so maybe I'm not seeing the same exact output you did.

I checked only the Vault contract so it's also possible that I missed some differences in one of the other contracts.

Details

Code size limit warning

curl -OL https://github.com/ethereum/solidity/files/6454709/original.txt
curl -OL https://github.com/ethereum/solidity/files/6454717/library.txt
curl -OL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.7.1+commit.f4a555be
chmod +x solc-linux-amd64-v0.7.1+commit.f4a555be

cat original.txt | jq .input | ./solc-linux-amd64-v0.7.1+commit.f4a555be --standard-json | jq .errors
cat library.txt | jq .input | ./solc-linux-amd64-v0.7.1+commit.f4a555be --standard-json | jq .errors

The output I see is null null, which means that there are no errors or warnings. I tried it also on versions 0.7.2..0.7.6 and I do get the code size limit warning there but consistently for both inputs.

Bytecode differences

I compared the bytecode of the Vault contract between the two inputs:

cat original.txt |
    jq .input |
    ./solc-linux-amd64-v0.7.1+commit.f4a555be --standard-json |
    jq '.contracts."contracts/vault/Vault.sol".Vault.evm.bytecode.object' |
    fold --width 80 > original-bytecode.json

cat library.txt |
    jq .input |
    ./solc-linux-amd64-v0.7.1+commit.f4a555be --standard-json |
    jq '.contracts."@balancer-labs/v2-core/contracts/vault/Vault.sol".Vault.evm.bytecode.object' |
    fold --width 80 > library-bytecode.json

diff --unified original-bytecode.json library-bytecode.json

I see two differences. One at the very end (clearly metadata) and one somewhere in the middle:

--- original-bytecode.json
+++ library-bytecode.json
@@ -630,7 +630,7 @@
 081fd5b5060209081020190565b60005b83811015615f3f578181015183820152602001615f27565
 b83811115610e005750506000910152565b6003811061057e57fe5b6001600160a01b03811681146
 1057e57600080fd5b801515811461057e57600080fd5b6003811061057e57600080fdfea26469706
-673582212207407ed1b393a303bec41b2d2138ea9f191487da85ca87bb09c513e6bc8ef1bd464736
+673582212205971f848ef1b21130755f833287121c5cff4f95bcc1a236b5f325019c39569a364736
 f6c6343000701003360c060405234801561001057600080fd5b50604051610be6380380610be6833
 98101604081905261002f9161004d565b30608052600160005560601b6001600160601b03191660a
 05261007b565b60006020828403121561005e578081fd5b81516001600160a01b038116811461007
@@ -706,5 +706,5 @@
 191600101610a7e565b50909695505050505050565b90815260200190565b9283526001600160a01
 b03918216602084015216604082015260600190565b60405181810167ffffffffffffffff8111828
 2101715610aed57600080fd5b604052919050565b6001600160a01b038116811461047b57600080f
-dfea2646970667358221220734348845c9fbcedea6792572efc730c04dbd48b23477ce93eb33a529
-03f7e7c64736f6c63430007010033"
+dfea2646970667358221220a4e1090a31d2b72650b91f04b91c556c9f7e6cb316b675531d76124e2
+83384aa64736f6c63430007010033"

To show that this is due to the metadata too we can set settings.metadata.bytecodeHash to "none" in the input and rerun:

cat original.txt | jq '.input * {settings: {metadata: {bytecodeHash: "none"}}}' > original-metadata-none.json
cat library.txt | jq '.input * {settings: {metadata: {bytecodeHash: "none"}}}' > library-metadata-none.json

cat original-metadata-none.json |
    ./solc-linux-amd64-v0.7.1+commit.f4a555be --standard-json |
    jq '.contracts."contracts/vault/Vault.sol".Vault.evm.bytecode.object' |
    fold --width 80 > original-metadata-none-bytecode.json

cat library-metadata-none.json |
    ./solc-linux-amd64-v0.7.1+commit.f4a555be --standard-json |
    jq '.contracts."@balancer-labs/v2-core/contracts/vault/Vault.sol".Vault.evm.bytecode.object' |
    fold --width 80 > library-metadata-none-bytecode.json

diff --unified original-metadata-none-bytecode.json library-metadata-none-bytecode.json

Here for me the output is empty, meaning that there are no differences.

@cameel cameel added the waiting for more input Issues waiting for more input by the reporter label Jun 24, 2021
@nventuro
Copy link
Contributor Author

Hey @cameel, thanks for the detailed analysis. Your comments about the metadata fields seem spot-on.

Unfortunately I built these two examples quite a while ago, and don't really recall exactly the steps I had taken to arrive at those two files :/ I'll try to revert to that state to reproduce this locally and share more details, but it is possible I might fail.

@cameel
Copy link
Member

cameel commented Dec 16, 2021

We have recently discovered a case where the bytecode is not reproducible with the same options unless you pass the same exact set of files to the compiler, even if the extra files are not actually used by your contract (see #12281 and #12415). Theoretically it could be what you saw but I only saw it happening on 0.6.12 and 0.7.0. I tested a few other versions, including 0.7.1 and they do not have this problem so I doubt it's this but I cannot exclude the possibility that you actually hit some other corner case that is reproducible on 0.7.1 after all.

I don't think we can do anything about this unless we get the input to inspect. I'm going to close this but feel free to reopen if you manage to reproduce it again.

@cameel cameel closed this as completed Dec 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 codegen error Compiler generates invalid code. Critical. waiting for more input Issues waiting for more input by the reporter
Projects
None yet
Development

No branches or pull requests

2 participants