10

Regarding the json build files that Truffle produces based off of my smart contract, is it safe for this information to be treated as public? I just want to be sure it doesn't contain any sensitive cryptographic signatures reserved for the contract producing address.

Thanks!

2 Answers 2

8

There are two problems with Truffle compilation output (JSON files), which make it difficult to keep them under version-control:

  1. The updatedAt field indicates the compilation time of the source file
  2. 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.

2
  • 1
    Excellent answer :) I wonder when Truffle would fix this issue of odd build files. Commented Jan 29, 2019 at 8:35
  • @LauriPeltonen: Thanks. Note: Tested on Truffle 4.x. Not sure about Truffle 5.x. Commented Jan 29, 2019 at 8:40
3

To start: yes you can commit them, there's nothing sensitive in them.

As far as I can tell, there is no real consensus about whether the build directory should be added to version control or not. Adding them mostly won't hurt, but it too has some side effects (the files contain some user-specific stuff).

OpenZeppelin seems to add the build directory into .gitignore so it's not version controlled. Consensys seems to include them.

You can read a bit more info for example here Best practice for sharing truffle build files between developers and here what is a standard .gitignore for truffle?

The beginning of a build folder JSON is something like this. The rest doesn't seem to be anything user-specific:

 "contractName": "Roles",
  "abi": [],
  "bytecode": "0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146080604052600080fd00a165627a7a723058205a377d3255ff69443ab46b8d5541e45781b31ce84c0aa4fc25cf6cc53b6194650029",
  "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fd00a165627a7a723058205a377d3255ff69443ab46b8d5541e45781b31ce84c0aa4fc25cf6cc53b6194650029",
  "sourceMap": "186:783:10:-;;132:2:-1;166:7;155:9;146:7;137:37;252:7;246:14;243:1;238:23;232:4;229:33;270:1;265:20;;;;222:63;;265:20;274:9;222:63;;298:9;295:1;288:20;328:4;319:7;311:22;352:7;343;336:24",
  "deployedSourceMap": "186:783:10:-;;;;;;;;",
  "source": "pragma solidity ^0.4.24;\n\n\n/**\n * @title Roles\n * @author Francisco Giordano (@frangio)\n * @dev Library for managing addresses assigned to a Role.\n * See RBAC.sol for example usage.\n */\nlibrary Roles {\n  struct Role {\n    mapping (address => bool) bearer;\n  }\n\n  /**\n   * @dev give an address access to this role\n   */\n  function add(Role storage role, address addr)\n    internal\n  {\n    role.bearer[addr] = true;\n  }\n\n  /**\n   * @dev remove an address' access to this role\n   */\n  function remove(Role storage role, address addr)\n    internal\n  {\n    role.bearer[addr] = false;\n  }\n\n  /**\n   * @dev check if an address has this role\n   * // reverts\n   */\n  function check(Role storage role, address addr)\n    view\n    internal\n  {\n    require(has(role, addr));\n  }\n\n  /**\n   * @dev check if an address has this role\n   * @return bool\n   */\n  function has(Role storage role, address addr)\n    view\n    internal\n    returns (bool)\n  {\n    return role.bearer[addr];\n  }\n}\n",
  "sourcePath": "C:\\Users\\Lauri\\Documents\\smart_contract\\contracts\\ownership\\rbac\\Roles.sol",
  "ast": {
    "absolutePath": "/C/Users/Lauri/Documents/smart_contract/contracts/ownership/rbac/Roles.sol",

So there are some user-specific folders.

2
  • "the files contain some user-specific stuff" - Do you by any chance know what user-specific stuff they contain (aside from absolute file paths)? Thank you!
    – Jay Welsh
    Commented Jan 28, 2019 at 20:17
  • Edited answer to add example Commented Jan 29, 2019 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.