Skip to content
This repository has been archived by the owner on Mar 11, 2024. It is now read-only.

truffle compile generates bytecode different from solc #77

Open
barakman opened this issue Oct 5, 2018 · 9 comments
Open

truffle compile generates bytecode different from solc #77

barakman opened this issue Oct 5, 2018 · 9 comments

Comments

@barakman
Copy link

barakman commented Oct 5, 2018

The bytecode generated by truffle compile and the bin generated by solc are always different.

I am using:

  • solc v0.4.24
  • truffle v4.1.14 (which, according to its package.json, relies on solc v0.4.24)

It appears that the difference is always in the 64 characters which appear right before the last 4 characters in each output. Is that possibly just metadata?

Anyhow, you can reproduce this as follows:

Input file MyContract.sol:

pragma solidity 0.4.24;
contract MyContract {
    uint public x = 42;
}

Truffle command-line:

truffle compile

Solc command-line:

solc --bin --output-dir=build/contracts contracts/MyContract.sol

Truffle output file MyContract.json:

{
  ...
  "bytecode": "0x6080604052602a600055348015601457600080fd5b50609e806100236000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600054815600a165627a7a7230582085d8b01651d23ddd6a24f980e190a61c86b692278463007d8ac2f5c74d4693100029",
  ...
}

Solc output file MyContract.bin:

6080604052602a600055348015601457600080fd5b50609e806100236000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600054815600a165627a7a72305820f18509eb242360daf2e9973ce555fa9a12f0e24589132507643b11daeef3e0440029

The difference:

T: 6080604052602a600055348015601457600080fd5b50609e806100236000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600054815600a165627a7a7230582085d8b01651d23ddd6a24f980e190a61c86b692278463007d8ac2f5c74d4693100029
S: 6080604052602a600055348015601457600080fd5b50609e806100236000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600054815600a165627a7a72305820f18509eb242360daf2e9973ce555fa9a12f0e24589132507643b11daeef3e0440029
@barakman
Copy link
Author

barakman commented Oct 5, 2018

OK, the answer is yes, this is just metadata.
For any future readers, it is stated explicitly in the Solidity documentation here.
Closing this issue.

@barakman barakman closed this as completed Oct 5, 2018
@barakman
Copy link
Author

barakman commented Oct 5, 2018

Second thought, why should Truffle generate different metadata than Solc?
Perhaps one of Truffle contributors would care to explain this, so I'm reopening this.

@barakman barakman reopened this Oct 5, 2018
@barakman
Copy link
Author

barakman commented Oct 7, 2018

Update:
The metadata seems to change when I rename the root folder, which implies that truffle compile embeds this information (path name) into the metadata.
This is not very useful when it comes to version control (also true with regards to the "updatedAt" field in each json file created by truffle compile, but at least that one doesn't impact the bytecode).
Any idea how to disable these features (i.e., force truffle compile to generate the same output for two identical input files, regardless of their location in the file system, and regardless of the time of compilation)?

@barakman
Copy link
Author

barakman commented Oct 7, 2018

Update #2:

I have located the reason for which truffle compile ultimately embeds the absolute path name of each input source file into the metadata part of the generated bytecode field.

It is located in the compile.with_dependencies function:

Object.keys(result).sort().forEach(function(import_path) {
  var display_path = import_path;
  if (path.isAbsolute(import_path)) {
    display_path = "." + path.sep + path.relative(options.working_directory, import_path);
  }
  options.logger.log("Compiling " + display_path + "...");
});

I order to prevent this undesired impact, the above code should be extended to:

Object.keys(result).sort().forEach(function(import_path) {
  var display_path = import_path;
  if (path.isAbsolute(import_path)) {
    display_path = "." + path.sep + path.relative(options.working_directory, import_path);
    result[display_path] = result[import_path];
    delete result[import_path];
  }
  options.logger.log("Compiling " + display_path + "...");
});

As you can see, on each iteration, if a key represents an absolute path, then I replace it with a relative path:

result[display_path] = result[import_path];
delete result[import_path];

It took me several hours to find the source of this problem and fix it.

With this "patch" applied, the only remaining feature which preserves the undesired behavior of truffle compile generating the same output for two identical input files (thus making it hard to manage the output under version control), is the "updatedAt" output field.

The fix for this one is much more straightforward (just look for this field in Truffle's source code).

@barakman
Copy link
Author

barakman commented Oct 7, 2018

Update #3:

Turns out the the fix above "causes havoc" when running solidity-coverage (which in turn, invokes truffle compile).

Therefore, a safer fix for this would be to use:

if (options.fix_paths) {
    result[display_path] = result[import_path];
    delete result[import_path];
}

And then, only when specifically desired, call truffle compile --fix_paths.

@wjmelements
Copy link

Thanks for documenting this!

@TT1943
Copy link

TT1943 commented Jun 20, 2020

I got the same issue. The bytecode generated is different from Waffle. This is critical when CREATE2 relies on the bytecode generated by different frameworks.

@enderphan94
Copy link

Facing the same issue, too annoying

@cameel
Copy link

cameel commented Jul 8, 2021

trufflesuite/truffle#4119 has now been implemented in Truffle meaning that there are no more absolute paths in metadata and bytecode does not depend on the project location. It will still be different from what solc produces by default due to the project:/ prefix added by Truffle to all files from project directory in compiler's JSON input.

The bytecode can be reproduced if you use solc --standard-json and manually add the prefix.

For example, if you have C.sol and D.sol inside contracts/, this is how the paths in the JSON input should look like to match Truffle:

{
    "language": "Solidity",
    "sources": {
        "project:/contracts/C.sol": { "content": "import \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";" },
        "project:/contracts/D.sol": { "content": "contract D {}" },
        "@openzeppelin/contracts/token/ERC20/IERC20.sol": { "content": "interface IERC20 { ... }" },
    },
    "settings": {"outputSelection": {"*": {"*": ["metadata", "evm.bytecode"]}}}
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants