There are two problems with Truffle compilation output (JSON files), which make it difficult to keep them under version-control:
- The
updatedAt
field indicates the compilation time of the source file
- The
bytecode
field encodes the absolute path of the source file
Due to problem #1, compiling the same input will always yield a different output.
Due to problem #2, compiling the same input on different machines may yield a different output.
Here is a method for working around these problems.
In file package.json
, add:
"scripts": {
"install": "node fix-truffle.js"
}
Next to file package.json
, add file fix-truffle.js
:
const fs = require("fs");
const FILE_NAME = "./node_modules/truffle/build/cli.bundled.js";
const OLD_STR = "display_path = \".\" + path.sep + path.relative(options.working_directory, import_path);";
const NEW_STR = "if (options.fix_paths) {display_path = \".\" + path.sep + path.relative(options.working_directory, import_path); result[display_path] = result[import_path]; delete result[import_path];}";
console.log("Fixing " + FILE_NAME);
const data = fs.readFileSync(FILE_NAME, {encoding: "utf8"});
fs.writeFileSync(FILE_NAME, data.split(OLD_STR).join(NEW_STR), {encoding: "utf8"});
Now, if you compile your contracts via truffle compile --all --fix_paths
, then identical input will always yield identical bytecode
output, regardless of the machine (or the file-system) where you execute this.
However, we still have the updatedAt
problem.
For this, you can add your own script for removing this field from the JSON file.
Alternatively, you can add a script which extracts the abi
and bytecode
fields from the JSON file, because this is all you really need operational-wise:
const fs = require("fs");
const INPUT_DIR = "your json files directory";
const OUTPUT_DIR = "your abi/bin files directory";
for (let fileName of fs.readdirSync(INPUT_DIR)) {
const data = JSON.parse(fs.readFileSync(INPUT_DIR + fileName, {encoding: "utf8"}));
fs.writeFileSync(OUTPUT_DIR + fileName.replace(".json", ".abi"), JSON.stringify(data.abi) , {encoding: "utf8"});
fs.writeFileSync(OUTPUT_DIR + fileName.replace(".json", ".bin"), data.bytecode.substring(2), {encoding: "utf8"});
}
Note that this gives you the same type of output (bin and abi files) as running solc
directly.
There is nevertheless one good excuse to insist on doing it with truffle
. Since you run your tests with truffle
, you want to be 100% certain that what you've tested is what you will eventually deploy. This is not guaranteed if you test with truffle
but then compile with solc
.