The main factor that enables reproducible builds is the addition of the trimpath flag in Go 1.13. This flag removed any references to local filesystem paths that end up in binaries. This is great for reproducibility, and also gets rid of some funny artifacts. For example, if you run an older version of Sia and print a stack trace, you’ll see a lot “/home/luke/” strings in there.
The next problem to solve before getting reproducibility was removing any other random or extraneous variables from the build process. This turned out to be quite simple! The build script used for releases would use the system time as the build time that gets stored in the binary. Rather than using system time that changes, the Sia build process uses the time of the top merge commit in the repository. An alternative would be to pass in a hardcoded time value. We also pass in a release tag to the build script, which is “v1.4.x” or similar. With this, we got deterministic builds. If you run the build scripts on the same source code locally (on any machine) you should get the same outputs consistently.non-deterministic -> deterministic!
The last puzzle piece needed for reproducibility is a build environment. There is a lot of other system noise that can get into binaries. To rid ourselves of it, we need to build from a stable environment. Right now that build environment is a Docker image with the basic requirements needed for building Go binaries. To use it you need to be running Linux on an x86–64 machine. That’s because Docker containers use the host kernel which can have effects in compilation output. In the future we can remove this OS and architecture requirement, by going even further with tools like gitian or guix.
Keep an eye out for an official announcement of any change to the build process, and for a repository to share signatures of binaries! The release-scripts directory on Gitlab contains all the scripts needed to build Sia and more detailed informatio...