From 2f1a7cff0ce6223338f18ea21b9038d5a1f8773d Mon Sep 17 00:00:00 2001 From: Demilade Sonuga Date: Tue, 21 Jan 2025 22:29:00 +0100 Subject: [PATCH] docker: add support for persistent state builds with docker --- Dockerfile => Dockerfile.ephemeral | 0 Dockerfile.persistent | 58 ++++++++++++++ README.md | 26 ++++++- .../persistent-docker-setup/conf/rusk.toml | 56 ++++++++++++++ scripts/persistent-docker-setup/detect_ips.sh | 54 +++++++++++++ scripts/persistent-docker-setup/setup.sh | 77 +++++++++++++++++++ 6 files changed, 269 insertions(+), 2 deletions(-) rename Dockerfile => Dockerfile.ephemeral (100%) create mode 100644 Dockerfile.persistent create mode 100644 scripts/persistent-docker-setup/conf/rusk.toml create mode 100755 scripts/persistent-docker-setup/detect_ips.sh create mode 100644 scripts/persistent-docker-setup/setup.sh diff --git a/Dockerfile b/Dockerfile.ephemeral similarity index 100% rename from Dockerfile rename to Dockerfile.ephemeral diff --git a/Dockerfile.persistent b/Dockerfile.persistent new file mode 100644 index 0000000000..a7b66f00d2 --- /dev/null +++ b/Dockerfile.persistent @@ -0,0 +1,58 @@ +# --- Build stage --- +FROM ubuntu:24.04 AS build-stage + +RUN apt-get update && apt-get install -y unzip curl build-essential openssl libssl-dev pkg-config && rm -rf /var/lib/apt/lists/* + +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + +WORKDIR /opt/rusk +ENV RUSK_PROFILE_PATH=/opt/dusk/rusk/ +ENV PATH="$PATH:/root/.cargo/bin" + +RUN apt-get update && apt-get install -y clang && rm -rf /var/lib/apt/lists/* + +COPY . . + +ARG TARGETPLATFORM +# See also https://github.com/docker/buildx/issues/510 +ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64} + +# Generate keys and compile genesis contracts +RUN make keys +RUN make wasm + +# Features to include in the build +# E.g., --build-arg CARGO_FEATURES="archive" +ARG NODE_TYPE="provisioner" + +RUN case "$NODE_TYPE" in \ + "provisioner") cargo build --release -p rusk ;; \ + "archive") cargo build --release --features archive -p rusk ;; \ + "prover") cargo build --release --no-default-features --features prover -p rusk ;; \ + *) echo "Unrecognized node type: $NODE_TYPE. Expected one of 'provisioner', 'archive' and 'prover'"; exit 1 ;; \ + esac + +# --- Run stage --- +FROM ubuntu:24.04 AS run-stage + +RUN apt-get update && apt-get install -y unzip curl net-tools libssl-dev && rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/dusk + +ENV RUSK_PROFILE_PATH=/opt/dusk/rusk +ENV RUSK_RECOVERY_INPUT=/opt/dusk/conf/genesis.toml +ENV RUST_BACKTRACE=full +ENV NETWORK=mainnet + +EXPOSE 9000/udp +EXPOSE 8080/tcp + +# Copy only the necessary files from the build stage +COPY --from=build-stage /opt/rusk/target/release/rusk /opt/dusk/bin/rusk +COPY --from=build-stage /opt/rusk/scripts/persistent-docker-setup/setup.sh /opt/dusk/setup.sh +COPY --from=build-stage /opt/rusk/scripts/persistent-docker-setup/detect_ips.sh /opt/dusk/detect_ips.sh +COPY --from=build-stage /opt/rusk/scripts/persistent-docker-setup/conf /opt/dusk/conf + +RUN chmod +x /opt/dusk/setup.sh /opt/dusk/detect_ips.sh + +CMD [ "./setup.sh" ] diff --git a/README.md b/README.md index 4bcb92a821..7bc3f25856 100644 --- a/README.md +++ b/README.md @@ -145,17 +145,19 @@ make wasm for=transfer ## 🐳 Docker support +### Local Ephemeral Node + It's also possible to run a local ephemeral node with Docker. To build the Docker image with archive: ```bash -docker build -t rusk . +docker build -f Dockerfile.ephemeral -t rusk . ``` To build the Docker image **without** archive: ```bash -docker build -t rusk --build-arg CARGO_FEATURES="" . +docker build -t -f Dockerfile.ephemeral rusk --build-arg CARGO_FEATURES="" . ``` To run Rusk inside a Docker container: @@ -166,6 +168,26 @@ docker run -p 9000:9000/udp -p 8080:8080/tcp rusk Port 9000 is used for Kadcast, port 8080 for the HTTP and GraphQL APIs. +### Persistent Node + +To build the docker image for a provisioner +```bash +docker build -f Dockerfile.persistent -t rusk --build-arg NODE_TYPE=provisioner . +``` + +To build for an archiver or prover instead, build with NODE_TYPE=archive or NODE_TYPE=prover, +respectively. + +To run: + +```bash +docker run -it \ + -v /path/to/consensus.keys:/opt/dusk/conf/consensus.keys + -v /path/to/rusk/profile:/opt/dusk/rusk \ + -e NETWORK=testnet \ + rusk +``` + ## License The Rusk software is licensed under the [Mozilla Public License Version 2.0](./LICENSE). diff --git a/scripts/persistent-docker-setup/conf/rusk.toml b/scripts/persistent-docker-setup/conf/rusk.toml new file mode 100644 index 0000000000..77444c45e4 --- /dev/null +++ b/scripts/persistent-docker-setup/conf/rusk.toml @@ -0,0 +1,56 @@ +# log_type = 'coloured' (default) +# log_type = 'json' + +# log_level = 'info' (default) +# log_filter = 'dusk_consensus=debug,node=debug,kadcast=debug' + +[chain] +genesis_timestamp = '' +generation_timeout = '3s' +db_path = '/opt/dusk/rusk' +consensus_keys_path = '/opt/dusk/conf/consensus.keys' +min_gas_limit = 150_000 +block_gas_limit = 3000000000 + +[databroker] +max_inv_entries = 100 +max_ongoing_requests = 1000 + +[mempool] +max_queue_size = 5000 +max_mempool_txn_count = 10000 +idle_interval = '5m' +mempool_expiry = '30m' +mempool_download_redundancy = 5 + +[kadcast] +kadcast_id = 0x0 +public_address = 'N/A' +listen_address = 'N/A' +bootstrapping_nodes = [] +auto_propagate = false +channel_size = 10000 +recursive_discovery = true + +[kadcast.bucket] +node_ttl = '120s' +node_evict_after = '15s' +bucket_ttl = '10m' +min_peers = 20 + +[kadcast.network] +udp_recv_buffer_size = 5000000 +# udp_send_backoff_timeout = '50us' +udp_send_retry_interval = '5ms' +udp_send_retry_count = 3 +blocklist_refresh_interval = '10s' + +[kadcast.fec.encoder] +min_repair_packets_per_block = 5 +mtu = 1300 +fec_redundancy = 0.15 + +[kadcast.fec.decoder] +cache_ttl = '1m' +cache_prune_every = '30s' +max_udp_len = 2097152 diff --git a/scripts/persistent-docker-setup/detect_ips.sh b/scripts/persistent-docker-setup/detect_ips.sh new file mode 100755 index 0000000000..6338eb83e8 --- /dev/null +++ b/scripts/persistent-docker-setup/detect_ips.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Fetch IPv4 WAN address using ifconfig.me, fallback to ipinfo.io +PUBLIC_IP=$(curl -4 -s https://ifconfig.me) +if [ -z "$PUBLIC_IP" ]; then + PUBLIC_IP=$(curl -4 -s https://ipinfo.io/ip) +fi + +# Validate IPv4 address +if [[ -z "$PUBLIC_IP" || ! "$PUBLIC_IP" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: Unable to retrieve a valid WAN IPv4 address" + exit 1 +fi + +runOnMac=false +int2ip() { printf ${2+-v} $2 "%d.%d.%d.%d" \ + $(($1>>24)) $(($1>>16&255)) $(($1>>8&255)) $(($1&255)) ;} +ip2int() { local _a=(${1//./ }) ; printf ${2+-v} $2 "%u" $(( _a<<24 | + ${_a[1]} << 16 | ${_a[2]} << 8 | ${_a[3]} )) ;} +while IFS=$' :\t\r\n' read a b c d; do + [ "$a" = "usage" ] && [ "$b" = "route" ] && runOnMac=true + if $runOnMac ;then + case $a in + gateway ) gWay=$b ;; + interface ) iFace=$b ;; + esac + else + [ "$a" = "0.0.0.0" ] && [ "$c" = "$a" ] && iFace=${d##* } gWay=$b + fi +done < <(/sbin/route -n 2>&1 || /sbin/route -n get 0.0.0.0/0) +ip2int $gWay gw +while read lhs rhs; do + [ "$lhs" ] && { + [ -z "${lhs#*:}" ] && iface=${lhs%:} + [ "$lhs" = "inet" ] && [ "$iface" = "$iFace" ] && { + mask=${rhs#*netmask } + mask=${mask%% *} + [ "$mask" ] && [ -z "${mask%0x*}" ] && + printf -v mask %u $mask || + ip2int $mask mask + ip2int ${rhs%% *} ip + (( ( ip & mask ) == ( gw & mask ) )) && + int2ip $ip myIp && int2ip $mask netMask + } + } +done < <(/sbin/ifconfig) + +echo "$PUBLIC_IP:9000" +if [ -z "$myIp" ]; then + echo "$PUBLIC_IP:9000" +else + echo "$myIp:9000" +fi + diff --git a/scripts/persistent-docker-setup/setup.sh b/scripts/persistent-docker-setup/setup.sh new file mode 100644 index 0000000000..169be02f04 --- /dev/null +++ b/scripts/persistent-docker-setup/setup.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -e + +echo "Starting node environment" + +configure_network() { + local network=$1 + local kadcast_id + local bootstrapping_nodes + local genesis_timestamp + local base_state + local prover_url + + case "$network" in + mainnet) + kadcast_id="0x1" + bootstrapping_nodes="['165.232.91.113:9000', '64.226.105.70:9000', '137.184.232.115:9000']" + genesis_timestamp="'2025-01-07T12:00:00Z'" + base_state="https://nodes.dusk.network/genesis-state" + prover_url="https://provers.dusk.network" + ;; + testnet) + kadcast_id="0x2" + bootstrapping_nodes="['134.122.62.88:9000','165.232.64.16:9000','137.184.118.43:9000']" + genesis_timestamp="'2024-12-23T17:00:00Z'" + base_state="https://testnet.nodes.dusk.network/genesis-state" + prover_url="https://testnet.provers.dusk.network" + ;; + devnet) + kadcast_id="0x3" + bootstrapping_nodes="['128.199.32.54', '159.223.29.22', '143.198.225.158']" + genesis_timestamp="'2024-12-23T12:00:00Z'" + base_state="https://devnet.nodes.dusk.network/genesis-state" + prover_url="https://devnet.provers.dusk.network" + ;; + *) + echo "Unknown network: $network. Defaulting to mainnet." + configure_network "mainnet" + return + ;; + esac + + # Create genesis.toml + cat > /opt/dusk/conf/genesis.toml <