Skip to content

Commit e9c950e

Browse files
authored
feat(devops): Improve usability of the docker-build command (#13)
# Motivation The `docker-build` command is used by many third parties, so needs to be accessible and have good --help. # Changes - Add a Dockerfile and supporting scripts - Add a README # Tests - The docker build is exercised in CI - The command line tool for running docker has been tested manually.
1 parent 6553fc1 commit e9c950e

File tree

10 files changed

+320
-3
lines changed

10 files changed

+320
-3
lines changed

.github/actions/build/action.yaml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: 'Docker Build'
2+
description: |
3+
Builds the artefacts for a standard release, including:
4+
* `signer.wasm.gz` (for all networks)
5+
inputs:
6+
no-cache:
7+
description: 'no-cache'
8+
default: false
9+
type: boolean
10+
runs:
11+
using: "composite"
12+
steps:
13+
- name: Set up docker buildx
14+
uses: docker/setup-buildx-action@v3
15+
- name: Build wasms
16+
uses: docker/build-push-action@v5
17+
with:
18+
context: .
19+
file: Dockerfile
20+
cache-from: type=gha,scope=cached-stage
21+
no-cache: ${{ inputs.no-cache || false }}
22+
# Exports the artefacts from the final stage
23+
outputs: out
24+
- name: 'Record the git commit and any tags'
25+
shell: bash
26+
run: |
27+
set -euxo pipefail
28+
git log | head -n1 > out/commit.txt
29+
- name: Hash artefacts
30+
shell: bash
31+
run: scripts/docker-hashes

.github/workflows/release.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Release
2+
on:
3+
push:
4+
branches:
5+
- setup-repo
6+
workflow_dispatch:
7+
inputs:
8+
no_cache:
9+
description: 'no-cache'
10+
default: false
11+
type: boolean
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
defaults:
16+
run:
17+
shell: bash -euxlo pipefail {0}
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 45
22+
env:
23+
GH_TOKEN: ${{ github.token }}
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
- name: Build
28+
uses: ./.github/actions/build

Dockerfile

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#
2+
# Reproducible Builds
3+
#
4+
5+
FROM ubuntu:22.04 AS base
6+
ENV TZ=UTC
7+
# Install basic tools
8+
RUN DEBIAN_FRONTEND=noninteractive apt update && apt install -y \
9+
curl \
10+
ca-certificates \
11+
build-essential \
12+
pkg-config \
13+
libssl-dev \
14+
llvm-dev \
15+
liblmdb-dev \
16+
clang \
17+
cmake \
18+
jq \
19+
&& rm -rf /var/lib/apt/lists/*
20+
21+
22+
# Gets dfx version
23+
#
24+
# Note: This can be done in the builder but is slow because unrelated changes to dfx.json can cause a rebuild.
25+
FROM base AS tool_versions
26+
SHELL ["bash", "-c"]
27+
RUN mkdir -p config
28+
COPY dfx.json dfx.json
29+
RUN jq -r .dfx dfx.json > config/dfx_version
30+
31+
32+
# Install tools && warm up the build cache
33+
FROM base AS builder
34+
SHELL ["bash", "-c"]
35+
# Install dfx
36+
# Note: dfx is installed in `$HOME/.local/share/dfx/bin` but we can't reference `$HOME` here so we hardcode `/root`.
37+
COPY --from=tool_versions /config/*_version config/
38+
ENV PATH="/root/.local/share/dfx/bin:${PATH}"
39+
RUN DFXVM_INIT_YES=true DFX_VERSION="$(cat config/dfx_version)" sh -c "$(curl -fsSL https://sdk.dfinity.org/install.sh)" && dfx --version
40+
# Install Rust
41+
COPY ./rust-toolchain.toml .
42+
ENV RUSTUP_HOME=/opt/rustup \
43+
CARGO_HOME=/cargo \
44+
PATH=/cargo/bin:$PATH
45+
COPY scripts/setup-rust scripts/setup-rust
46+
RUN scripts/setup-rust
47+
# Optional: Pre-build dependencies
48+
COPY Cargo.lock .
49+
COPY Cargo.toml .
50+
COPY src/signer/Cargo.toml src/signer/Cargo.toml
51+
COPY src/example-backend/Cargo.toml src/example-backend/Cargo.toml
52+
COPY src/shared/Cargo.toml src/shared/Cargo.toml
53+
ENV CARGO_TARGET_DIR=/cargo_target
54+
RUN mkdir -p src/signer/src \
55+
&& touch src/signer/src/lib.rs \
56+
&& mkdir -p src/shared/src \
57+
&& touch src/shared/src/lib.rs \
58+
&& mkdir -p src/example-backend/src \
59+
&& touch src/example-backend/src/lib.rs \
60+
&& cargo build --target wasm32-unknown-unknown \
61+
&& rm -rf src
62+
63+
64+
# Builds canister: example-backend
65+
FROM builder AS build-example-backend
66+
COPY src src
67+
COPY dfx.json dfx.json
68+
COPY canister_ids.json canister_ids.json
69+
RUN touch src/*/src/*.rs
70+
RUN dfx build --ic example-backend
71+
RUN cp .dfx/ic/canisters/example-backend/example-backend.wasm /example-backend.wasm.gz
72+
RUN sha256sum /example-backend.wasm.gz
73+
74+
FROM scratch AS example-backend
75+
COPY --from=build-example-backend /example-backend.wasm.gz /
76+
77+
# Builds canister: signer
78+
FROM builder AS build-signer
79+
COPY src src
80+
COPY dfx.json dfx.json
81+
COPY canister_ids.json canister_ids.json
82+
RUN touch src/*/src/*.rs
83+
RUN dfx build --ic signer
84+
RUN cp .dfx/ic/canisters/signer/signer.wasm.gz /signer.wasm.gz
85+
RUN sha256sum /signer.wasm.gz
86+
87+
FROM scratch AS signer
88+
COPY --from=build-signer /signer.wasm.gz /

README.md

+72-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,73 @@
1-
# chain-fusion-signer
1+
![alt text](image.png)
22

3-
A canister that does nothing but sign transactions for use on other blockchains.
3+
<br/>
4+
<br/>
5+
6+
[![Internet Computer portal](https://img.shields.io/badge/Internet-Computer-grey?logo=internet%20computer)](https://internetcomputer.org)
7+
[![Code checks](https://github.com/dfinity/chain-fusion-signer/actions/workflows/check.yml/badge.svg)](https://github.com/dfinity/chain-fusion-signer/actions/workflows/check.yml)
8+
9+
</div>
10+
11+
---
12+
13+
# What is the Chain Fusion Signer
14+
15+
The Internet Computer provides an API that allows any canister to hold decentralised public-private key pairs. These keys can be used to sign messages for any system that uses compatible elliptic curves. Popular use cases are signing Bitcoin and Ethereum transactions. However, accessing this API requires developing a backend canister, which may be an unnecessary hurdle. The Chain Fusion Signer makes the Internet Computer threshold signature APIs directly accessible to web apps and to command line users.
16+
17+
## Use Cases
18+
19+
### Front-end application development
20+
21+
A front end web developer can now develop a multi-chain web app using the following generic components:
22+
23+
- An asset canister, for serving HTML, images and Javascript.
24+
- An identity provider for login.
25+
- The Chain Fusion Signer to interact with blockchains.
26+
- A generic data store for user profiles; developers have a wide choice of SQL and NoSQL databases that run on the Internet Computer.
27+
28+
### Command Line
29+
30+
Users can now hold keys on-chain and sign with the command line with a simple `dfx canister call`, without having to deploy or maintain their own signing canister.
31+
32+
# Governance
33+
34+
### Ownership
35+
36+
The Chain Fusion Signer is intended to have ownership equivalent to the Internet Computer threshold signing APIs. The purpose of the Chain Fusion Signer is ONLY to make the Internet Computer signing APIs more accessible.
37+
38+
### Payment
39+
40+
Threshold signatures require cycles. As such, API users must attach cycles for their calls, either directly or via a payment protocol.
41+
42+
### Update Cadence
43+
44+
The chain fusion signer is made to be very stable. It would be black-holed but the requirement to be able to make security updates precludes that. However, after an initial teething phase, updates should be very rare and performed only with strong community support, similar to the support required to add the threshold signing APIs in the first place. Upgrade should occur ONLY when:
45+
46+
- There is a security flaw that needs to be addressed.
47+
- The Internet Computer threshold signing APIs change. For example, if the Internet Computer adds support for an additional elliptic curve, the Chain Fusion Signer should make that improvement available to web developers.
48+
- In very limited cases, utilities may be added to the Chain Fusion Signer to support common use cases. Restraint should be exercised here. Convenience functions that can be implemented in the browser should be implemented in the browser. Convenience functions should address only very common, well established use cases.
49+
50+
### Maintainance
51+
52+
The Chain Fusion Signer code should be very simple and maintaible, so that any developer with a strong record of making trustworthy, secure cryptographic applications can maintain it.
53+
54+
Any developer who wishes to make changes to the Chain Fusion Signer SHOULD:
55+
56+
- Communicate with the community, e.g. via the forums, to verify that their intended changes have support.
57+
- Communicate with other maintainers, to ensure that changes do not conflict.
58+
- Submit changes in small units, ideally of under 100 lines per change.
59+
- Ensure that a well known and trusted auditor checks the code.
60+
61+
### Verifiability
62+
63+
The code can be built reproducibly with:
64+
65+
```
66+
./scripts/docker-build
67+
```
68+
69+
# Usage
70+
71+
Please refer to the canister .did file to the API.
72+
73+
TODO: Examples and developer-friendly documentation.

canister_ids.json

+3
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
"signer": {
33
"ic": "grghe-syaaa-aaaar-qabyq-cai",
44
"staging": "tdxud-2yaaa-aaaad-aadiq-cai"
5+
},
6+
"example-backend": {
7+
"ic": "2vxsx-fae"
58
}
69
}

image.png

1.08 MB
Loading

scripts/did.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ function generate_did() {
1515

1616
CANISTERS=signer
1717

18-
for canister in $(echo $CANISTERS | sed "s/,/ /g"); do
18+
for canister in ${CANISTERS//,/ }; do
1919
generate_did "$canister"
2020
done

scripts/docker-build

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
(("${BASH_VERSINFO[0]}" >= 5)) || {
5+
echo "ERROR: Please use a newer version of bash. The minimum supported bash version is 5. Yours appears to be '${BASH_VERSINFO[0]}'" >&2
6+
exit 1
7+
}
8+
9+
if test -d scripts && test -e Dockerfile; then
10+
: "OK: We appear to be in the root of the repo."
11+
else
12+
echo "ERROR: Please run from the root of the chain-fusion-signer git repository." >&2
13+
exit 1
14+
fi
15+
16+
DFX_TARGET=signer
17+
OUTDIR=out
18+
PROGRESS="--progress=auto"
19+
image_name="chain-fusion-signer"
20+
21+
print_help() {
22+
cat <<-"EOF"
23+
24+
Build signer.wasm.gz inside docker. This creates:
25+
- An "out" directory in the project directory containing all build artefacts.
26+
Note: If the "out" directory already exists, it will be deleted and replaced.
27+
28+
EOF
29+
}
30+
31+
print_docker_help() {
32+
cat <<-"EOF"
33+
Note: If the docker build fails, it may help to build from a clean cache:
34+
35+
./scripts/docker-build -- --no-cache
36+
37+
EOF
38+
}
39+
40+
if [[ "${1:-}" == "--help" ]]; then
41+
print_help
42+
exit 0
43+
fi
44+
45+
if DOCKER_BUILDKIT=1 docker build \
46+
--target "$DFX_TARGET" \
47+
"$PROGRESS" \
48+
-t "$image_name" \
49+
-o "$OUTDIR" . \
50+
"${@+${@}}"; then
51+
echo "SUCCESS: Docker build has succeeded."
52+
scripts/docker-hashes
53+
else
54+
set +x
55+
{
56+
echo "ERROR: Docker build failed."
57+
print_docker_help
58+
exit 1
59+
} >&2
60+
fi
61+
62+
echo FIN

scripts/docker-hashes

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
# Note:
3+
# * `sha256sum` prints the hash of each file;
4+
# * The `wc -c` in the awk code gets the size in bytes of each file;
5+
# * The AWK code also adds a header and footer;
6+
# * `column -t` formats the data as a table;
7+
# * `tee` saves a copy of the printout in a file; that file will be included in releases.
8+
find out/ -type f -print0 | xargs sha256sum | awk '{"wc -c " $2 | getline size; print $1, size}BEGIN{print "===START_ARTEFACTS===\nsha256 size filename"}END{print "==END_ARTEFACTS=="}' | column -t | tee out/filelist.txt

scripts/setup-rust

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
# Installs rust
3+
4+
set -euo pipefail
5+
6+
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
cd "$SCRIPTS_DIR/.."
8+
9+
function run() {
10+
echo 1>&2 "running $*"
11+
rc=0 && "$@" || rc="$?"
12+
if ! [ "$rc" -eq 0 ]; then
13+
echo 1>&2 "Bootstrap command failed: $*"
14+
exit "$rc"
15+
fi
16+
}
17+
18+
rust_version=$(sed -n 's/^channel[[:space:]]*=[[:space:]]"\(.*\)"/\1/p' rust-toolchain.toml)
19+
echo "using rust version '$rust_version'"
20+
21+
# here we set the toolchain to 'none' and rustup will pick up on ./rust-toolchain.toml
22+
run curl --fail https://sh.rustup.rs -sSf | run sh -s -- -y --default-toolchain "none" --no-modify-path
23+
24+
# make sure the packages are actually installed (rustup waits for the first invoke to lazyload)
25+
cargo --version
26+
cargo clippy --version
27+
cargo fmt --version

0 commit comments

Comments
 (0)