From 8dda896e4b2c4baa69b5e1b839bfaf47b9b36320 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Wed, 30 Nov 2022 11:11:29 +0100 Subject: [PATCH 1/8] guix: Linux reproducible builds of the daemon --- Cargo.toml | 3 -- contrib/guix/build.sh | 21 ++++++++++ contrib/guix/guix-build.sh | 78 ++++++++++++++++++++++++++++++++++++++ contrib/guix/manifest.scm | 5 +++ 4 files changed, 104 insertions(+), 3 deletions(-) create mode 100755 contrib/guix/build.sh create mode 100755 contrib/guix/guix-build.sh create mode 100644 contrib/guix/manifest.scm diff --git a/Cargo.toml b/Cargo.toml index ddd3b20a..197ea29d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,3 @@ libc = "0.2" # Used for PSBTs base64 = "0.13" - -[patch.crates-io] - diff --git a/contrib/guix/build.sh b/contrib/guix/build.sh new file mode 100755 index 00000000..a3d8f396 --- /dev/null +++ b/contrib/guix/build.sh @@ -0,0 +1,21 @@ +set -ex + +# Guix comes with Cargo 1.52 but --config was stabilized in 1.63, so we need +# to specify unstable-options. +# We use the --config to redirect cargo toward our vendored source directory +# for our dependencies. +# TODO: build in release mode +cargo -Z unstable-options -vvv \ + --color always \ + --frozen \ + --offline \ + rustc \ + --release \ + --target-dir "$TARGET_DIR" \ + --config source.vendored_sources.directory=\""$VENDOR_DIR"\" \ + --config source.crates-io.replace-with=\"vendored_sources\" \ + --config source.\"https://github.com/darosior/rust-miniscript\".replace-with=\"vendored_sources\" \ + --config source.\"https://github.com/darosior/rust-miniscript\".git=\"https://github.com/darosior/rust-miniscript\" \ + --config source.\"https://github.com/darosior/rust-miniscript\".branch=\"multipath_descriptors_on_8.0\" + +set +ex diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh new file mode 100755 index 00000000..d7325245 --- /dev/null +++ b/contrib/guix/guix-build.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env sh + +set -ex + +# How many cores to allocate to Guix building. +JOBS="${JOBS:-$(nproc)}" + +# The binary to check the hash of downloaded archives. +SHASUM_BIN="${SHASUM_BIN:-sha256sum}" + +# We do everything in a single directory. That's the root of it, configurable +# through the environment. +BUILD_ROOT="${BUILD_ROOT:-$(mktemp -d)}" + +# Various folders we expose to the container. The vendor directory will contain +# the sources of all our dependencies. Because we restrict network access from +# within the container, this is pulled beforehand. +# The out directory will contain the resulting binaries. It's wired to the --target-dir +# for a cargo build. +VENDOR_DIR="$BUILD_ROOT/vendor" +OUT_DIR="${OUT_DIR:-"$BUILD_ROOT/out"}" +BIN_DIR="${BIN_DIR:-"$BUILD_ROOT/bin"}" + +# Create the various folders if the root build directory is fresh. +for d in "$OUT_DIR" "$BIN_DIR"; do + if ! [ -d "$d" ]; then + mkdir -p "$d" + fi +done + +# That's what Guix comes with. +RUST_VERSION="1.52.0" +CARGO_BIN="$BIN_DIR/cargo" + +# First off get the cargo binary to run on the host to vendor dependencies. +# We assume the host is a 64bit Linux system. +if ! [ -f "$CARGO_BIN" ]; then + ARCHIVE_PATH="$BIN_DIR/rust-for-cargo.tar.gz" + curl -o "$ARCHIVE_PATH" "https://static.rust-lang.org/dist/rust-$RUST_VERSION-x86_64-unknown-linux-gnu.tar.gz" + echo "c082b5eea81206ff207407b41a10348282362dd972e93c86b054952b66ca0e2b $ARCHIVE_PATH" | $SHASUM_BIN -c + # Path of the cargo binary within the archive + CARGO_BIN_PATH="rust-$RUST_VERSION-x86_64-unknown-linux-gnu/cargo/bin/cargo" + ( cd $BIN_DIR && tar -xzf $ARCHIVE_PATH $CARGO_BIN_PATH && mv $CARGO_BIN_PATH $CARGO_BIN ) +fi + +# Pull the sources of our dependencies before building them in the container. +if ! [ -d "$VENDOR_DIR" ]; then + $CARGO_BIN vendor $VENDOR_DIR +fi + +# Execute "$@" in a pinned, possibly older version of Guix, for reproducibility +# across time. +time_machine() { + guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \ + --commit=059d38dc3f8b087f4a42df586daeb05761ee18d7 \ + --cores="$JOBS" \ + --keep-failed \ + --fallback \ + -- "$@" +} + +# Bootstrap a reproducible environment as specified by the manifest in an isolated +# container, and build the project. +time_machine shell --no-cwd \ + --expose="$PWD/src=/liana/src" \ + --expose="$PWD/Cargo.toml=/liana/Cargo.toml" \ + --expose="$PWD/Cargo.lock=/liana/Cargo.lock" \ + --expose="$PWD/contrib/guix/build.sh=/liana/build.sh" \ + --expose="$VENDOR_DIR=$VENDOR_DIR" \ + --share="$OUT_DIR=$OUT_DIR" \ + --container \ + -m $PWD/contrib/guix/manifest.scm \ + -- env CC=clang VENDOR_DIR="$VENDOR_DIR" TARGET_DIR="$OUT_DIR" \ + /bin/sh -c "cd /liana && ./build.sh" + +set +ex + +echo "Build successful. Output available at $OUT_DIR" diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm new file mode 100644 index 00000000..564884a3 --- /dev/null +++ b/contrib/guix/manifest.scm @@ -0,0 +1,5 @@ +(specifications->manifest + (list "rust" + "rust-cargo" + "coreutils" + "clang-toolchain")) From 3906a1b5bc5e7f57925981b4dd009fc6b13de7c1 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Thu, 1 Dec 2022 17:21:06 +0100 Subject: [PATCH 2/8] guix: reproducible builds of the GUI The GUI is using an insane MSRV so i had to patch my way through in order to be able to build some dependencies. --- contrib/guix/build.sh | 37 +- contrib/guix/guix-build.sh | 94 +++- contrib/guix/manifest.scm | 10 +- .../guix/patches/gui/iced_default_enum.patch | 459 ++++++++++++++++++ 4 files changed, 561 insertions(+), 39 deletions(-) create mode 100644 contrib/guix/patches/gui/iced_default_enum.patch diff --git a/contrib/guix/build.sh b/contrib/guix/build.sh index a3d8f396..2377693a 100755 --- a/contrib/guix/build.sh +++ b/contrib/guix/build.sh @@ -1,21 +1,34 @@ set -ex -# Guix comes with Cargo 1.52 but --config was stabilized in 1.63, so we need -# to specify unstable-options. -# We use the --config to redirect cargo toward our vendored source directory -# for our dependencies. -# TODO: build in release mode -cargo -Z unstable-options -vvv \ +# Instruct cargo to use our vendored sources +mkdir -p ~/.cargo +cat <~/.cargo/config.toml +[source.vendored_sources] +directory = "$VENDOR_DIR" + +[source.crates-io] +replace-with = "vendored_sources" + +[source."https://github.com/darosior/rust-miniscript"] +git = "https://github.com/darosior/rust-miniscript" +branch = "multipath_descriptors_on_8.0" +replace-with = "vendored_sources" + +[source."https://github.com/revault/liana"] +git = "https://github.com/revault/liana" +branch = "master" +replace-with = "vendored_sources" +EOF + +# We need to set RUSTC_BOOTSTRAP=1 as a workaround to be able to use unstable +# features in the GUI dependencies +# FIXME: GUIX_LD_WRAPPER_DISABLE_RPATH=yes +RUSTC_BOOTSTRAP=1 cargo -vvv \ --color always \ --frozen \ --offline \ rustc \ --release \ - --target-dir "$TARGET_DIR" \ - --config source.vendored_sources.directory=\""$VENDOR_DIR"\" \ - --config source.crates-io.replace-with=\"vendored_sources\" \ - --config source.\"https://github.com/darosior/rust-miniscript\".replace-with=\"vendored_sources\" \ - --config source.\"https://github.com/darosior/rust-miniscript\".git=\"https://github.com/darosior/rust-miniscript\" \ - --config source.\"https://github.com/darosior/rust-miniscript\".branch=\"multipath_descriptors_on_8.0\" + --target-dir "$TARGET_DIR" set +ex diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh index d7325245..368a0ad8 100755 --- a/contrib/guix/guix-build.sh +++ b/contrib/guix/guix-build.sh @@ -21,15 +21,16 @@ VENDOR_DIR="$BUILD_ROOT/vendor" OUT_DIR="${OUT_DIR:-"$BUILD_ROOT/out"}" BIN_DIR="${BIN_DIR:-"$BUILD_ROOT/bin"}" -# Create the various folders if the root build directory is fresh. -for d in "$OUT_DIR" "$BIN_DIR"; do - if ! [ -d "$d" ]; then - mkdir -p "$d" +# Create the directory if it doesn't exist already +maybe_create_dir() { + if ! [ -d "$@" ]; then + mkdir -p "$@" fi -done +} +maybe_create_dir "$BIN_DIR" # That's what Guix comes with. -RUST_VERSION="1.52.0" +RUST_VERSION="1.60.0" CARGO_BIN="$BIN_DIR/cargo" # First off get the cargo binary to run on the host to vendor dependencies. @@ -37,17 +38,12 @@ CARGO_BIN="$BIN_DIR/cargo" if ! [ -f "$CARGO_BIN" ]; then ARCHIVE_PATH="$BIN_DIR/rust-for-cargo.tar.gz" curl -o "$ARCHIVE_PATH" "https://static.rust-lang.org/dist/rust-$RUST_VERSION-x86_64-unknown-linux-gnu.tar.gz" - echo "c082b5eea81206ff207407b41a10348282362dd972e93c86b054952b66ca0e2b $ARCHIVE_PATH" | $SHASUM_BIN -c + echo "b8a4c3959367d053825e31f90a5eb86418eb0d80cacda52bfa80b078e18150d5 $ARCHIVE_PATH" | $SHASUM_BIN -c # Path of the cargo binary within the archive CARGO_BIN_PATH="rust-$RUST_VERSION-x86_64-unknown-linux-gnu/cargo/bin/cargo" ( cd $BIN_DIR && tar -xzf $ARCHIVE_PATH $CARGO_BIN_PATH && mv $CARGO_BIN_PATH $CARGO_BIN ) fi -# Pull the sources of our dependencies before building them in the container. -if ! [ -d "$VENDOR_DIR" ]; then - $CARGO_BIN vendor $VENDOR_DIR -fi - # Execute "$@" in a pinned, possibly older version of Guix, for reproducibility # across time. time_machine() { @@ -59,19 +55,67 @@ time_machine() { -- "$@" } -# Bootstrap a reproducible environment as specified by the manifest in an isolated -# container, and build the project. -time_machine shell --no-cwd \ - --expose="$PWD/src=/liana/src" \ - --expose="$PWD/Cargo.toml=/liana/Cargo.toml" \ - --expose="$PWD/Cargo.lock=/liana/Cargo.lock" \ - --expose="$PWD/contrib/guix/build.sh=/liana/build.sh" \ - --expose="$VENDOR_DIR=$VENDOR_DIR" \ - --share="$OUT_DIR=$OUT_DIR" \ - --container \ - -m $PWD/contrib/guix/manifest.scm \ - -- env CC=clang VENDOR_DIR="$VENDOR_DIR" TARGET_DIR="$OUT_DIR" \ - /bin/sh -c "cd /liana && ./build.sh" +# Build both the daemon (at the root of the repository) and the GUI (in gui/) +for project_folder in "" "gui"; do + PROJECT_ROOT="$PWD/$project_folder" + PROJECT_VENDOR_DIR="$VENDOR_DIR/$project_folder" + PROJECT_OUT_DIR="$OUT_DIR/$project_folder" + PROJECT_PATCHES_ROOT="$PWD/contrib/guix/patches/$project_folder" + + project_needs_patches() { + test $(ls -A1q "$PROJECT_PATCHES_ROOT" |grep patch) + } + + maybe_create_dir "$PROJECT_OUT_DIR" + + # Pull the sources of our dependencies before building them in the container. + if ! [ -d "$PROJECT_VENDOR_DIR" ]; then + # Download the dependencies + ( cd "$project_folder" && $CARGO_BIN vendor "$PROJECT_VENDOR_DIR" ) + + # Patch some dependencies sources if needed for this project + if project_needs_patches; then + ( + cd "$PROJECT_VENDOR_DIR" + for patch_file in $(ls "$PROJECT_PATCHES_ROOT"); do + patch -p1 < "$PROJECT_PATCHES_ROOT/$patch_file" + done + ) + + # Some of the checksums will be incorrect. Instead of cherry-picking remove them + # altogether, since they aren't useful anyways (see comment below). + for dep in $(ls "$PROJECT_VENDOR_DIR"); do + echo "{\"files\":{}}" > "$PROJECT_VENDOR_DIR/$dep/.cargo-checksum.json" + done + fi + fi + + cp "$PROJECT_ROOT/Cargo.lock" "$BUILD_ROOT/Cargo.lock" + if project_needs_patches; then + # Remove the checksums from the Cargo.lock. In the container `cargo rustc` would compare + # them against the .cargo-checksum.json to make sure they weren't tampered with since they + # where vendored. But we just removed the checksums from the .cargo-checksum.json. + # There is little point in checking integrity between the above vendor step and now anyways. + # What matters is checking integrity after downloading the crates from the internet and + # `cargo vendor` does that already. + sed -i '/checksum/d' "$BUILD_ROOT/Cargo.lock" + fi + + # Bootstrap a reproducible environment as specified by the manifest in an isolated + # container, and build the project. + time_machine shell --no-cwd \ + --expose="$PROJECT_ROOT/src=/liana/src" \ + --expose="$PWD/gui/static=/liana/static" \ + --expose="$PROJECT_ROOT/Cargo.toml=/liana/Cargo.toml" \ + --expose="$BUILD_ROOT/Cargo.lock=/liana/Cargo.lock" \ + --expose="$PWD/contrib/guix/build.sh=/liana/build.sh" \ + --expose="$PROJECT_VENDOR_DIR=$PROJECT_VENDOR_DIR" \ + --share="$PROJECT_OUT_DIR=$PROJECT_OUT_DIR" \ + --container \ + -m $PWD/contrib/guix/manifest.scm \ + -- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" \ + /bin/sh -c "cd /liana && ./build.sh" +done set +ex diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 564884a3..f3ec6b0a 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -1,5 +1,11 @@ +;; FIXME: Only pull the GUI dependencies when building it, not the daemon (specifications->manifest (list "rust" - "rust-cargo" + "rust:cargo" "coreutils" - "clang-toolchain")) + "pkg-config" ;; For the GUI + "eudev" ;; For the GUI + "cmake" ;; For the GUI + "make" ;; For the GUI + "fontconfig" ;; For the GUI + "gcc-toolchain@10.3.0")) diff --git a/contrib/guix/patches/gui/iced_default_enum.patch b/contrib/guix/patches/gui/iced_default_enum.patch new file mode 100644 index 00000000..e040e9aa --- /dev/null +++ b/contrib/guix/patches/gui/iced_default_enum.patch @@ -0,0 +1,459 @@ +commit f71bc71bf6724a1c5e2a3246dd8bd0a90fcf0e15 +Author: Antoine Poinsot +Date: Thu Dec 1 15:38:32 2022 +0100 + + Do not use, or special-case them, unstable features as of 1.60.0 + + This is in order to make the GUI MSRV effectively 1.60.0. + + Default derivation on enums is removed. + + Usage of bool_to_option is removed. + + Generic associated types is unfortunately special cased as enabled. This + forces use to set RUSTC_BOOTSTRAP=1 in the Guix container... + +diff --git a/iced_glow/src/lib.rs b/iced_glow/src/lib.rs +index e3690a69..b5b9cc38 100644 +--- a/iced_glow/src/lib.rs ++++ b/iced_glow/src/lib.rs +@@ -20,6 +20,7 @@ + #![forbid(rust_2018_idioms)] + #![allow(clippy::inherent_to_string, clippy::type_complexity)] + #![cfg_attr(docsrs, feature(doc_cfg))] ++#![feature(generic_associated_types)] + + pub use glow; + +diff --git a/iced_graphics/src/lib.rs b/iced_graphics/src/lib.rs +index d39dd90c..876b478f 100644 +--- a/iced_graphics/src/lib.rs ++++ b/iced_graphics/src/lib.rs +@@ -21,6 +21,7 @@ + #![forbid(rust_2018_idioms)] + #![allow(clippy::inherent_to_string, clippy::type_complexity)] + #![cfg_attr(docsrs, feature(doc_cfg))] ++#![feature(generic_associated_types)] + mod antialiasing; + mod error; + mod primitive; +diff --git a/iced_native/src/program/state.rs b/iced_native/src/program/state.rs +index 8ae1cacb..25a3028b 100644 +--- a/iced_native/src/program/state.rs ++++ b/iced_native/src/program/state.rs +@@ -120,7 +120,11 @@ where + .iter() + .zip(event_statuses) + .filter_map(|(event, status)| { +- matches!(status, event::Status::Ignored).then_some(event) ++ if matches!(status, event::Status::Ignored) { ++ Some(event) ++ } else { ++ None ++ } + }) + .cloned() + .collect(); +diff --git a/iced_style/src/theme.rs b/iced_style/src/theme.rs +index d7ebb827..224a04fc 100644 +--- a/iced_style/src/theme.rs ++++ b/iced_style/src/theme.rs +@@ -25,10 +25,9 @@ use iced_core::{Background, Color, Vector}; + use std::rc::Rc; + + /// A built-in theme. +-#[derive(Debug, Clone, PartialEq, Default)] ++#[derive(Debug, Clone, PartialEq)] + pub enum Theme { + /// The built-in light variant. +- #[default] + Light, + /// The built-in dark variant. + Dark, +@@ -61,6 +60,12 @@ impl Theme { + } + } + ++impl Default for Theme { ++ fn default() -> Self { ++ Self::Light ++ } ++} ++ + /// A [`Theme`] with a customized [`Palette`]. + #[derive(Debug, Clone, Copy, PartialEq)] + pub struct Custom { +@@ -79,15 +84,19 @@ impl Custom { + } + + /// The style of an application. +-#[derive(Default)] + pub enum Application { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for Application { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl application::StyleSheet for Theme { + type Style = Application; + +@@ -119,10 +128,11 @@ impl From application::Appearance> for Application { + } + + /// The style of a button. +-#[derive(Default)] ++/* ++ * Button ++ */ + pub enum Button { + /// The primary style. +- #[default] + Primary, + /// The secondary style. + Secondary, +@@ -138,6 +148,12 @@ pub enum Button { + Custom(Box>), + } + ++impl Default for Button { ++ fn default() -> Self { ++ Self::Primary ++ } ++} ++ + impl button::StyleSheet for Theme { + type Style = Button; + +@@ -227,10 +243,11 @@ impl button::StyleSheet for Theme { + } + + /// The style of a checkbox. +-#[derive(Default)] ++/* ++ * Checkbox ++ */ + pub enum Checkbox { + /// The primary style. +- #[default] + Primary, + /// The secondary style. + Secondary, +@@ -242,6 +259,12 @@ pub enum Checkbox { + Custom(Box>), + } + ++impl Default for Checkbox { ++ fn default() -> Self { ++ Self::Primary ++ } ++} ++ + impl checkbox::StyleSheet for Theme { + type Style = Checkbox; + +@@ -339,10 +362,11 @@ fn checkbox_appearance( + } + + /// The style of a container. +-#[derive(Default)] ++/* ++ * Container ++ */ + pub enum Container { + /// No style. +- #[default] + Transparent, + /// A simple box. + Box, +@@ -350,6 +374,12 @@ pub enum Container { + Custom(Box>), + } + ++impl Default for Container { ++ fn default() -> Self { ++ Self::Transparent ++ } ++} ++ + impl From container::Appearance> for Container { + fn from(f: fn(&Theme) -> container::Appearance) -> Self { + Self::Custom(Box::new(f)) +@@ -387,15 +417,19 @@ impl container::StyleSheet for fn(&Theme) -> container::Appearance { + } + + /// The style of a slider. +-#[derive(Default)] + pub enum Slider { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for Slider { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl slider::StyleSheet for Theme { + type Style = Slider; + +@@ -468,15 +502,20 @@ impl slider::StyleSheet for Theme { + } + + /// The style of a menu. +-#[derive(Clone, Default)] ++#[derive(Clone)] + pub enum Menu { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Rc>), + } + ++impl Default for Menu { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl menu::StyleSheet for Theme { + type Style = Menu; + +@@ -510,10 +549,9 @@ impl From for Menu { + } + + /// The style of a pick list. +-#[derive(Clone, Default)] ++#[derive(Clone)] + pub enum PickList { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom( +@@ -522,6 +560,12 @@ pub enum PickList { + ), + } + ++impl Default for PickList { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl pick_list::StyleSheet for Theme { + type Style = PickList; + +@@ -565,15 +609,19 @@ impl pick_list::StyleSheet for Theme { + } + + /// The style of a radio button. +-#[derive(Default)] + pub enum Radio { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for Radio { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl radio::StyleSheet for Theme { + type Style = Radio; + +@@ -620,15 +668,19 @@ impl radio::StyleSheet for Theme { + } + + /// The style of a toggler. +-#[derive(Default)] + pub enum Toggler { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for Toggler { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl toggler::StyleSheet for Theme { + type Style = Toggler; + +@@ -687,15 +739,19 @@ impl toggler::StyleSheet for Theme { + } + + /// The style of a pane grid. +-#[derive(Default)] + pub enum PaneGrid { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for PaneGrid { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl pane_grid::StyleSheet for Theme { + type Style = PaneGrid; + +@@ -729,10 +785,11 @@ impl pane_grid::StyleSheet for Theme { + } + + /// The style of a progress bar. +-#[derive(Default)] ++/* ++ * Progress Bar ++ */ + pub enum ProgressBar { + /// The primary style. +- #[default] + Primary, + /// The success style. + Success, +@@ -742,6 +799,12 @@ pub enum ProgressBar { + Custom(Box>), + } + ++impl Default for ProgressBar { ++ fn default() -> Self { ++ Self::Primary ++ } ++} ++ + impl From progress_bar::Appearance> for ProgressBar { + fn from(f: fn(&Theme) -> progress_bar::Appearance) -> Self { + Self::Custom(Box::new(f)) +@@ -782,15 +845,22 @@ impl progress_bar::StyleSheet for fn(&Theme) -> progress_bar::Appearance { + } + + /// The style of a rule. +-#[derive(Default)] ++/* ++ * Rule ++ */ + pub enum Rule { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for Rule { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl From rule::Appearance> for Rule { + fn from(f: fn(&Theme) -> rule::Appearance) -> Self { + Self::Custom(Box::new(f)) +@@ -824,15 +894,19 @@ impl rule::StyleSheet for fn(&Theme) -> rule::Appearance { + } + + /// The style of a scrollable. +-#[derive(Default)] + pub enum Scrollable { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for Scrollable { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl scrollable::StyleSheet for Theme { + type Style = Scrollable; + +@@ -889,15 +963,23 @@ impl scrollable::StyleSheet for Theme { + } + + /// The style of text. +-#[derive(Clone, Copy, Default)] ++/* ++ * Text ++ */ ++#[derive(Clone, Copy)] + pub enum Text { + /// The default style. +- #[default] + Default, + /// Colored text. + Color(Color), + } + ++impl Default for Text { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl From for Text { + fn from(color: Color) -> Self { + Text::Color(color) +@@ -916,15 +998,19 @@ impl text::StyleSheet for Theme { + } + + /// The style of a text input. +-#[derive(Default)] + pub enum TextInput { + /// The default style. +- #[default] + Default, + /// A custom style. + Custom(Box>), + } + ++impl Default for TextInput { ++ fn default() -> Self { ++ Self::Default ++ } ++} ++ + impl text_input::StyleSheet for Theme { + type Style = TextInput; + +diff --git a/iced_wgpu/src/lib.rs b/iced_wgpu/src/lib.rs +index dcb699e8..5b3cda57 100644 +--- a/iced_wgpu/src/lib.rs ++++ b/iced_wgpu/src/lib.rs +@@ -37,6 +37,7 @@ + #![forbid(rust_2018_idioms)] + #![allow(clippy::inherent_to_string, clippy::type_complexity)] + #![cfg_attr(docsrs, feature(doc_cfg))] ++#![feature(generic_associated_types)] + + pub mod settings; + pub mod triangle; + From 940c28d072c449295f6e1225446b829bea2d3053 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Sat, 3 Dec 2022 13:03:01 +0100 Subject: [PATCH 3/8] guix: use patchelf to strip interpreter and RPATH --- contrib/guix/build.sh | 8 +++++++- contrib/guix/guix-build.sh | 12 +++++++++++- contrib/guix/manifest.scm | 3 +-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/contrib/guix/build.sh b/contrib/guix/build.sh index 2377693a..44fbf773 100755 --- a/contrib/guix/build.sh +++ b/contrib/guix/build.sh @@ -22,7 +22,6 @@ EOF # We need to set RUSTC_BOOTSTRAP=1 as a workaround to be able to use unstable # features in the GUI dependencies -# FIXME: GUIX_LD_WRAPPER_DISABLE_RPATH=yes RUSTC_BOOTSTRAP=1 cargo -vvv \ --color always \ --frozen \ @@ -31,4 +30,11 @@ RUSTC_BOOTSTRAP=1 cargo -vvv \ --release \ --target-dir "$TARGET_DIR" +# Assume 64bits. Even bitcoind doesn't ship 32bits binaries for x86. +# FIXME: is there a cleaner way than using patchelf for this? +patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 "$TARGET_DIR/release/$BINARY_NAME" + +# FIXME: Find a way to use GUIX_LD_WRAPPER_DISABLE_RPATH=yes instead +patchelf --remove-rpath "$TARGET_DIR/release/$BINARY_NAME" + set +ex diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh index 368a0ad8..8ac2ffe9 100755 --- a/contrib/guix/guix-build.sh +++ b/contrib/guix/guix-build.sh @@ -101,6 +101,16 @@ for project_folder in "" "gui"; do sed -i '/checksum/d' "$BUILD_ROOT/Cargo.lock" fi + # FIXME: find a cleaner way to get the binary name, or get rid of patchelf entirely + if [ "$project_folder" = "" ]; then + BINARY_NAME="lianad" + elif [ "$project_folder" = "gui" ]; then + BINARY_NAME="liana-gui" + else + echo "Can't determine binary name" + exit 1 + fi + # Bootstrap a reproducible environment as specified by the manifest in an isolated # container, and build the project. time_machine shell --no-cwd \ @@ -113,7 +123,7 @@ for project_folder in "" "gui"; do --share="$PROJECT_OUT_DIR=$PROJECT_OUT_DIR" \ --container \ -m $PWD/contrib/guix/manifest.scm \ - -- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" \ + -- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" BINARY_NAME="$BINARY_NAME" \ /bin/sh -c "cd /liana && ./build.sh" done diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index f3ec6b0a..515bf822 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -5,7 +5,6 @@ "coreutils" "pkg-config" ;; For the GUI "eudev" ;; For the GUI - "cmake" ;; For the GUI - "make" ;; For the GUI "fontconfig" ;; For the GUI + "patchelf" "gcc-toolchain@10.3.0")) From ae0b24f97494a7a859578ab6191187c4405a225f Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Sat, 3 Dec 2022 14:55:50 +0100 Subject: [PATCH 4/8] guix: allow to limit the number of cores dedicated to the build --- contrib/guix/build.sh | 1 + contrib/guix/guix-build.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/guix/build.sh b/contrib/guix/build.sh index 44fbf773..a5a6df43 100755 --- a/contrib/guix/build.sh +++ b/contrib/guix/build.sh @@ -27,6 +27,7 @@ RUSTC_BOOTSTRAP=1 cargo -vvv \ --frozen \ --offline \ rustc \ + --jobs "$JOBS" \ --release \ --target-dir "$TARGET_DIR" diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh index 8ac2ffe9..7bcd6de5 100755 --- a/contrib/guix/guix-build.sh +++ b/contrib/guix/guix-build.sh @@ -121,9 +121,10 @@ for project_folder in "" "gui"; do --expose="$PWD/contrib/guix/build.sh=/liana/build.sh" \ --expose="$PROJECT_VENDOR_DIR=$PROJECT_VENDOR_DIR" \ --share="$PROJECT_OUT_DIR=$PROJECT_OUT_DIR" \ + --cores="$JOBS" \ --container \ -m $PWD/contrib/guix/manifest.scm \ - -- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" BINARY_NAME="$BINARY_NAME" \ + -- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" BINARY_NAME="$BINARY_NAME" JOBS="$JOBS" \ /bin/sh -c "cd /liana && ./build.sh" done From 37a28dbf7d5a22426d1844ef792d04e604e5b91b Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Sat, 3 Dec 2022 15:48:01 +0100 Subject: [PATCH 5/8] guix: use a lighter environment for building the daemon Special case the GUI dependencies to the GUI's container --- contrib/guix/guix-build.sh | 5 +++-- contrib/guix/manifest.scm | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh index 7bcd6de5..52bbeda8 100755 --- a/contrib/guix/guix-build.sh +++ b/contrib/guix/guix-build.sh @@ -102,10 +102,11 @@ for project_folder in "" "gui"; do fi # FIXME: find a cleaner way to get the binary name, or get rid of patchelf entirely + # Note: we also rely on it in manifest.scm if [ "$project_folder" = "" ]; then - BINARY_NAME="lianad" + export BINARY_NAME="lianad" elif [ "$project_folder" = "gui" ]; then - BINARY_NAME="liana-gui" + export BINARY_NAME="liana-gui" else echo "Can't determine binary name" exit 1 diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 515bf822..64eb5375 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -1,10 +1,15 @@ -;; FIXME: Only pull the GUI dependencies when building it, not the daemon (specifications->manifest - (list "rust" - "rust:cargo" - "coreutils" - "pkg-config" ;; For the GUI - "eudev" ;; For the GUI - "fontconfig" ;; For the GUI - "patchelf" - "gcc-toolchain@10.3.0")) + (append + (list "rust" + "rust:cargo" + "coreutils" + "patchelf" + "gcc-toolchain@10.3.0") + ;; Additional dependencies for building the GUI + (let ((binary_name (getenv "BINARY_NAME"))) + (if + (string=? "liana-gui" binary_name) + (list "pkg-config" + "eudev" + "fontconfig") + '())))) From 4a38040acf12dd457ac5f29a24f4b3800114255c Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Sun, 4 Dec 2022 19:36:42 +0100 Subject: [PATCH 6/8] guix: documentation This is directly inspired from the Bitcoin Core project's documentation. This especially copies some stuff written by Carl Dong. --- contrib/guix/README.md | 176 +++++++++++++++++++++++++++++++++++++++++ contrib/guix/build.sh | 4 + 2 files changed, 180 insertions(+) create mode 100644 contrib/guix/README.md diff --git a/contrib/guix/README.md b/contrib/guix/README.md new file mode 100644 index 00000000..c6dacda9 --- /dev/null +++ b/contrib/guix/README.md @@ -0,0 +1,176 @@ +## Bootstrappable Liana builds + +This repository contains the scripts to perform [reproducible](https://reproducible-builds.org/) and +[bootstrappable](https://bootstrappable.org/) builds of Liana using [Guix](https://guix.gnu.org/), a +functional package manager. + +For a short high-level introduction to the purpose of bootstrappable builds, see [this +talk](https://www.youtube.com/watch?v=I2iShmUTEl8) by Carl Dong in the context of the Bitcoin Core +project. + +For now, only `x86_64` Linux binaries are supported. We aim to extend bootstrappable builds to more +targets in the future. + + +### Installation + +See the very [detailed document about GUIX installation in the Bitcoin Core +project](https://github.com/bitcoin/bitcoin/blob/master/contrib/guix/INSTALL.md). Almost all of it +is directly applicable to Liana as well. + + +### Usage + +First of all, you need to decide on the amount of trust in the building process. Of course this +decision needs to fall within a broader threat model, but it is still interesting to consider. + +*(Note: this section was taken from the Bitcoin Core documentation and initially written by Carl +Dong.)* + +#### Choosing your security model + +No matter how you installed Guix, you need to decide on your security model for +building packages with Guix. + +Guix allows us to achieve better binary security by using our CPU time to build +everything from scratch. However, it doesn't sacrifice user choice in pursuit of +this: users can decide whether or not to use **substitutes** (pre-built +packages). + +##### Option 1: Building with substitutes + +###### Step 1: Authorize the signing keys + +Depending on the installation procedure you followed, you may have already +authorized the Guix build farm key. In particular, the official shell installer +script asks you if you want the key installed, and the debian distribution +package authorized the key during installation. + +You can check the current list of authorized keys at `/etc/guix/acl`. + +At the time of writing, a `/etc/guix/acl` with just the Guix build farm key +authorized looks something like: + +```lisp +(acl + (entry + (public-key + (ecc + (curve Ed25519) + (q #8D156F295D24B0D9A86FA5741A840FF2D24F60F7B6C4134814AD55625971B394#) + ) + ) + (tag + (guix import) + ) + ) + ) +``` + +If you've determined that the official Guix build farm key hasn't been +authorized, and you would like to authorize it, run the following as root: + +``` +guix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub +``` + +If +`/var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub` +doesn't exist, try: + +```sh +guix archive --authorize < /share/guix/ci.guix.gnu.org.pub +``` + +Where `` is likely: +- `/usr` if you installed from a distribution package +- `/usr/local` if you installed Guix from source and didn't supply any + prefix-modifying flags to Guix's `./configure` + +For dongcarl's substitute server at https://guix.carldong.io, run as root: + +```sh +wget -qO- 'https://guix.carldong.io/signing-key.pub' | guix archive --authorize +``` + +To remove previously authorized keys, simply edit `/etc/guix/acl` and remove the +`(entry (public-key ...))` entry. + +###### Step 2: Specify the substitute servers + +Once its key is authorized, the official Guix build farm at +https://ci.guix.gnu.org is automatically used unless the `--no-substitutes` flag +is supplied. This default list of substitute servers is overridable both on a +`guix-daemon` level and when you invoke `guix` commands. See examples below for +the various ways of adding dongcarl's substitute server after having [authorized +his signing key](#step-1-authorize-the-signing-keys). + +Change the **default list** of substitute servers by starting `guix-daemon` with +the `--substitute-urls` option (you will likely need to edit your init script): + +```sh +guix-daemon --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org' +``` + +Override the default list of substitute servers by passing the +`--substitute-urls` option for invocations of `guix` commands: + +```sh +guix --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org' +``` + +For scripts under `./contrib/guix`, set the `SUBSTITUTE_URLS` environment +variable: + +```sh +export SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org' +``` + +##### Option 2: Disabling substitutes on an ad-hoc basis + +If you prefer not to use any substitutes, make sure to supply `--no-substitutes` +like in the following snippet. The first build will take a while, but the +resulting packages will be cached for future builds. + +For direct invocations of `guix`: +```sh +guix --no-substitutes +``` + +The build script doesn't yet allow you to provide this via an environment variable, you'd +have to modify it yourself (or contribute a patch :p). + +##### Option 3: Disabling substitutes by default + +`guix-daemon` accepts a `--no-substitutes` flag, which will make sure that, +unless otherwise overridden by a command line invocation, no substitutes will be +used. + +If you start `guix-daemon` using an init script, you can edit said script to +supply this flag. + + +#### Building Liana + +For both the daemon (`lianad`) and the GUI (`liana-gui`), the [`guix-build.sh`](./guix-build.sh) +script will vendor the dependencies of the project (as pinned in the `Cargo.lock`) and start a [GUIX +container](https://guix.gnu.org/manual/devel/en/html_node/Invoking-guix-shell.html) that will run +the `build.sh` script that will take care of building the dependencies and the project using `cargo`. + +To start a build, simply run the `guix-build.sh` script from the root of the repository: +``` +$ ./contrib/guix/guix-build.sh +``` + +The script shouldn't contain any bash-ism, so it should work with other shells as well. + + +#### Customization + +Environment variables are available to configure the build. + +`BUILD_ROOT` allows you to specify the root folder that will contain the vendored dependencies' +source, the build cache as well as the resulting binaries (in `$BUILD_ROOT/out`). + +`JOBS` allows you to specify the number of cores to dedicate to the build both for bootstrapping the +toolchain with GUIX and building the project using `cargo`. diff --git a/contrib/guix/build.sh b/contrib/guix/build.sh index a5a6df43..f5c3c6f3 100755 --- a/contrib/guix/build.sh +++ b/contrib/guix/build.sh @@ -1,3 +1,7 @@ +# ========================================================================== +# The script ran within the GUIX container to build the Liana daemon or GUI. +# ========================================================================== + set -ex # Instruct cargo to use our vendored sources From 72a332d2caf6c139d20855203d107fe3b185ba7d Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Mon, 5 Dec 2022 11:00:51 +0100 Subject: [PATCH 7/8] guix: fix the dependencies listing for the GUI container --- contrib/guix/guix-build.sh | 12 +++++++++--- contrib/guix/manifest.scm | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh index 52bbeda8..e749bc00 100755 --- a/contrib/guix/guix-build.sh +++ b/contrib/guix/guix-build.sh @@ -104,9 +104,9 @@ for project_folder in "" "gui"; do # FIXME: find a cleaner way to get the binary name, or get rid of patchelf entirely # Note: we also rely on it in manifest.scm if [ "$project_folder" = "" ]; then - export BINARY_NAME="lianad" + BINARY_NAME="lianad" elif [ "$project_folder" = "gui" ]; then - export BINARY_NAME="liana-gui" + BINARY_NAME="liana-gui" else echo "Can't determine binary name" exit 1 @@ -114,7 +114,10 @@ for project_folder in "" "gui"; do # Bootstrap a reproducible environment as specified by the manifest in an isolated # container, and build the project. - time_machine shell --no-cwd \ + # NOTE: it looks like "--rebuild-cache" is necessary for the BINARY_NAME variable to + # be taken into account when building the container (otherwise the GUI container could + # miss some dependencies). + BINARY_NAME="$BINARY_NAME" time_machine shell --no-cwd \ --expose="$PROJECT_ROOT/src=/liana/src" \ --expose="$PWD/gui/static=/liana/static" \ --expose="$PROJECT_ROOT/Cargo.toml=/liana/Cargo.toml" \ @@ -124,6 +127,9 @@ for project_folder in "" "gui"; do --share="$PROJECT_OUT_DIR=$PROJECT_OUT_DIR" \ --cores="$JOBS" \ --container \ + --pure \ + --fallback \ + --rebuild-cache \ -m $PWD/contrib/guix/manifest.scm \ -- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" BINARY_NAME="$BINARY_NAME" JOBS="$JOBS" \ /bin/sh -c "cd /liana && ./build.sh" diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 64eb5375..5ea7a81a 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -8,7 +8,7 @@ ;; Additional dependencies for building the GUI (let ((binary_name (getenv "BINARY_NAME"))) (if - (string=? "liana-gui" binary_name) + (string=? binary_name "liana-gui") (list "pkg-config" "eudev" "fontconfig") From ef20b782301bae2fdfb842dfd89a749e60cb449e Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Mon, 5 Dec 2022 11:55:53 +0100 Subject: [PATCH 8/8] guix: make the builds actually reproducible Paths to the dependencies affect the symbols in the binary --- contrib/guix/build.sh | 8 ++++---- contrib/guix/guix-build.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/guix/build.sh b/contrib/guix/build.sh index f5c3c6f3..7c9f00a5 100755 --- a/contrib/guix/build.sh +++ b/contrib/guix/build.sh @@ -8,7 +8,7 @@ set -ex mkdir -p ~/.cargo cat <~/.cargo/config.toml [source.vendored_sources] -directory = "$VENDOR_DIR" +directory = "/vendor" [source.crates-io] replace-with = "vendored_sources" @@ -33,13 +33,13 @@ RUSTC_BOOTSTRAP=1 cargo -vvv \ rustc \ --jobs "$JOBS" \ --release \ - --target-dir "$TARGET_DIR" + --target-dir "/out" # Assume 64bits. Even bitcoind doesn't ship 32bits binaries for x86. # FIXME: is there a cleaner way than using patchelf for this? -patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 "$TARGET_DIR/release/$BINARY_NAME" +patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 "/out/release/$BINARY_NAME" # FIXME: Find a way to use GUIX_LD_WRAPPER_DISABLE_RPATH=yes instead -patchelf --remove-rpath "$TARGET_DIR/release/$BINARY_NAME" +patchelf --remove-rpath "/out/release/$BINARY_NAME" set +ex diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh index e749bc00..816b3466 100755 --- a/contrib/guix/guix-build.sh +++ b/contrib/guix/guix-build.sh @@ -123,8 +123,8 @@ for project_folder in "" "gui"; do --expose="$PROJECT_ROOT/Cargo.toml=/liana/Cargo.toml" \ --expose="$BUILD_ROOT/Cargo.lock=/liana/Cargo.lock" \ --expose="$PWD/contrib/guix/build.sh=/liana/build.sh" \ - --expose="$PROJECT_VENDOR_DIR=$PROJECT_VENDOR_DIR" \ - --share="$PROJECT_OUT_DIR=$PROJECT_OUT_DIR" \ + --expose="$PROJECT_VENDOR_DIR=/vendor" \ + --share="$PROJECT_OUT_DIR=/out" \ --cores="$JOBS" \ --container \ --pure \