truffle-compile
truffle-compile copied to clipboard
truffle compile generates bytecode different from solc
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
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.
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.
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)?
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).
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
.
Thanks for documenting this!
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.
Facing the same issue, too annoying
https://github.com/trufflesuite/truffle/issues/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"]}}}
}